diff options
Diffstat (limited to 'src/js/view')
-rw-r--r-- | src/js/view/mxCellEditor.js | 522 | ||||
-rw-r--r-- | src/js/view/mxCellOverlay.js | 233 | ||||
-rw-r--r-- | src/js/view/mxCellRenderer.js | 1480 | ||||
-rw-r--r-- | src/js/view/mxCellState.js | 375 | ||||
-rw-r--r-- | src/js/view/mxCellStatePreview.js | 223 | ||||
-rw-r--r-- | src/js/view/mxConnectionConstraint.js | 42 | ||||
-rw-r--r-- | src/js/view/mxEdgeStyle.js | 1302 | ||||
-rw-r--r-- | src/js/view/mxGraph.js | 11176 | ||||
-rw-r--r-- | src/js/view/mxGraphSelectionModel.js | 435 | ||||
-rw-r--r-- | src/js/view/mxGraphView.js | 2545 | ||||
-rw-r--r-- | src/js/view/mxLayoutManager.js | 375 | ||||
-rw-r--r-- | src/js/view/mxMultiplicity.js | 257 | ||||
-rw-r--r-- | src/js/view/mxOutline.js | 649 | ||||
-rw-r--r-- | src/js/view/mxPerimeter.js | 484 | ||||
-rw-r--r-- | src/js/view/mxPrintPreview.js | 801 | ||||
-rw-r--r-- | src/js/view/mxSpaceManager.js | 460 | ||||
-rw-r--r-- | src/js/view/mxStyleRegistry.js | 70 | ||||
-rw-r--r-- | src/js/view/mxStylesheet.js | 266 | ||||
-rw-r--r-- | src/js/view/mxSwimlaneManager.js | 449 | ||||
-rw-r--r-- | src/js/view/mxTemporaryCellStates.js | 105 |
20 files changed, 0 insertions, 22249 deletions
diff --git a/src/js/view/mxCellEditor.js b/src/js/view/mxCellEditor.js deleted file mode 100644 index 2086cca..0000000 --- a/src/js/view/mxCellEditor.js +++ /dev/null @@ -1,522 +0,0 @@ -/** - * $Id: mxCellEditor.js,v 1.62 2012-12-11 16:59:31 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellEditor - * - * In-place editor for the graph. To control this editor, use - * <mxGraph.invokesStopCellEditing>, <mxGraph.enterStopsCellEditing> and - * <mxGraph.escapeEnabled>. If <mxGraph.enterStopsCellEditing> is true then - * ctrl-enter or shift-enter can be used to create a linefeed. The F2 and - * escape keys can always be used to stop editing. To customize the location - * of the textbox in the graph, override <getEditorBounds> as follows: - * - * (code) - * graph.cellEditor.getEditorBounds = function(state) - * { - * var result = mxCellEditor.prototype.getEditorBounds.apply(this, arguments); - * - * if (this.graph.getModel().isEdge(state.cell)) - * { - * result.x = state.getCenterX() - result.width / 2; - * result.y = state.getCenterY() - result.height / 2; - * } - * - * return result; - * }; - * (end) - * - * The textarea uses the mxCellEditor CSS class. You can modify this class in - * your custom CSS. Note: You should modify the CSS after loading the client - * in the page. - * - * Example: - * - * To only allow numeric input in the in-place editor, use the following code. - * - * (code) - * var text = graph.cellEditor.textarea; - * - * mxEvent.addListener(text, 'keydown', function (evt) - * { - * if (!(evt.keyCode >= 48 && evt.keyCode <= 57) && - * !(evt.keyCode >= 96 && evt.keyCode <= 105)) - * { - * mxEvent.consume(evt); - * } - * }); - * (end) - * - * Initial values: - * - * To implement an initial value for cells without a label, use the - * <emptyLabelText> variable. - * - * Resize in Chrome: - * - * Resize of the textarea is disabled by default. If you want to enable - * this feature extend <init> and set this.textarea.style.resize = ''. - * - * Constructor: mxCellEditor - * - * Constructs a new in-place editor for the specified graph. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxCellEditor(graph) -{ - this.graph = graph; -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellEditor.prototype.graph = null; - -/** - * Variable: textarea - * - * Holds the input textarea. Note that this may be null before the first - * edit. Instantiated in <init>. - */ -mxCellEditor.prototype.textarea = null; - -/** - * Variable: editingCell - * - * Reference to the <mxCell> that is currently being edited. - */ -mxCellEditor.prototype.editingCell = null; - -/** - * Variable: trigger - * - * Reference to the event that was used to start editing. - */ -mxCellEditor.prototype.trigger = null; - -/** - * Variable: modified - * - * Specifies if the label has been modified. - */ -mxCellEditor.prototype.modified = false; - -/** - * Variable: emptyLabelText - * - * Text to be displayed for empty labels. Default is ''. This can be set - * to eg. "[Type Here]" to easier visualize editing of empty labels. The - * value is only displayed before the first keystroke and is never used - * as the actual editin value. - */ -mxCellEditor.prototype.emptyLabelText = ''; - -/** - * Variable: textNode - * - * Reference to the label DOM node that has been hidden. - */ -mxCellEditor.prototype.textNode = ''; - -/** - * Function: init - * - * Creates the <textarea> and installs the event listeners. The key handler - * updates the <modified> state. - */ -mxCellEditor.prototype.init = function () -{ - this.textarea = document.createElement('textarea'); - - this.textarea.className = 'mxCellEditor'; - this.textarea.style.position = 'absolute'; - this.textarea.style.overflow = 'visible'; - - this.textarea.setAttribute('cols', '20'); - this.textarea.setAttribute('rows', '4'); - - if (mxClient.IS_GC) - { - this.textarea.style.resize = 'none'; - } - - mxEvent.addListener(this.textarea, 'blur', mxUtils.bind(this, function(evt) - { - this.focusLost(); - })); - - mxEvent.addListener(this.textarea, 'keydown', mxUtils.bind(this, function(evt) - { - if (!mxEvent.isConsumed(evt)) - { - if (evt.keyCode == 113 /* F2 */ || (this.graph.isEnterStopsCellEditing() && - evt.keyCode == 13 /* Enter */ && !mxEvent.isControlDown(evt) && - !mxEvent.isShiftDown(evt))) - { - this.graph.stopEditing(false); - mxEvent.consume(evt); - } - else if (evt.keyCode == 27 /* Escape */) - { - this.graph.stopEditing(true); - mxEvent.consume(evt); - } - else - { - // Clears the initial empty label on the first keystroke - if (this.clearOnChange) - { - this.clearOnChange = false; - this.textarea.value = ''; - } - - // Updates the modified flag for storing the value - this.setModified(true); - } - } - })); -}; - -/** - * Function: isModified - * - * Returns <modified>. - */ -mxCellEditor.prototype.isModified = function() -{ - return this.modified; -}; - -/** - * Function: setModified - * - * Sets <modified> to the specified boolean value. - */ -mxCellEditor.prototype.setModified = function(value) -{ - this.modified = value; -}; - -/** - * Function: focusLost - * - * Called if the textarea has lost focus. - */ -mxCellEditor.prototype.focusLost = function() -{ - this.stopEditing(!this.graph.isInvokesStopCellEditing()); -}; - -/** - * Function: startEditing - * - * Starts the editor for the given cell. - * - * Parameters: - * - * cell - <mxCell> to start editing. - * trigger - Optional mouse event that triggered the editor. - */ -mxCellEditor.prototype.startEditing = function(cell, trigger) -{ - // Lazy instantiates textarea to save memory in IE - if (this.textarea == null) - { - this.init(); - } - - this.stopEditing(true); - var state = this.graph.getView().getState(cell); - - if (state != null) - { - this.editingCell = cell; - this.trigger = trigger; - this.textNode = null; - - if (state.text != null && this.isHideLabel(state)) - { - this.textNode = state.text.node; - this.textNode.style.visibility = 'hidden'; - } - - // Configures the style of the in-place editor - var scale = this.graph.getView().scale; - var size = mxUtils.getValue(state.style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE) * scale; - var family = mxUtils.getValue(state.style, mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY); - var color = mxUtils.getValue(state.style, mxConstants.STYLE_FONTCOLOR, 'black'); - var align = (this.graph.model.isEdge(state.cell)) ? mxConstants.ALIGN_LEFT : - mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_LEFT); - var bold = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD; - var italic = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC; - var uline = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE; - - this.textarea.style.fontSize = size + 'px'; - this.textarea.style.fontFamily = family; - this.textarea.style.textAlign = align; - this.textarea.style.color = color; - this.textarea.style.fontWeight = (bold) ? 'bold' : 'normal'; - this.textarea.style.fontStyle = (italic) ? 'italic' : ''; - this.textarea.style.textDecoration = (uline) ? 'underline' : ''; - - // Specifies the bounds of the editor box - var bounds = this.getEditorBounds(state); - - this.textarea.style.left = bounds.x + 'px'; - this.textarea.style.top = bounds.y + 'px'; - this.textarea.style.width = bounds.width + 'px'; - this.textarea.style.height = bounds.height + 'px'; - this.textarea.style.zIndex = 5; - - var value = this.getInitialValue(state, trigger); - - // Uses an optional text value for empty labels which is cleared - // when the first keystroke appears. This makes it easier to see - // that a label is being edited even if the label is empty. - if (value == null || value.length == 0) - { - value = this.getEmptyLabelText(); - this.clearOnChange = true; - } - else - { - this.clearOnChange = false; - } - - this.setModified(false); - this.textarea.value = value; - this.graph.container.appendChild(this.textarea); - - if (this.textarea.style.display != 'none') - { - // FIXME: Doesn't bring up the virtual keyboard on iPad - this.textarea.focus(); - this.textarea.select(); - } - } -}; - -/** - * Function: stopEditing - * - * Stops the editor and applies the value if cancel is false. - */ -mxCellEditor.prototype.stopEditing = function(cancel) -{ - cancel = cancel || false; - - if (this.editingCell != null) - { - if (this.textNode != null) - { - this.textNode.style.visibility = 'visible'; - this.textNode = null; - } - - if (!cancel && this.isModified()) - { - this.graph.labelChanged(this.editingCell, this.getCurrentValue(), this.trigger); - } - - this.editingCell = null; - this.trigger = null; - this.textarea.blur(); - this.textarea.parentNode.removeChild(this.textarea); - } -}; - -/** - * Function: getInitialValue - * - * Gets the initial editing value for the given cell. - */ -mxCellEditor.prototype.getInitialValue = function(state, trigger) -{ - return this.graph.getEditingValue(state.cell, trigger); -}; - -/** - * Function: getCurrentValue - * - * Returns the current editing value. - */ -mxCellEditor.prototype.getCurrentValue = function() -{ - return this.textarea.value.replace(/\r/g, ''); -}; - -/** - * Function: isHideLabel - * - * Returns true if the label should be hidden while the cell is being - * edited. - */ -mxCellEditor.prototype.isHideLabel = function(state) -{ - return true; -}; - -/** - * Function: getMinimumSize - * - * Returns the minimum width and height for editing the given state. - */ -mxCellEditor.prototype.getMinimumSize = function(state) -{ - var scale = this.graph.getView().scale; - - return new mxRectangle(0, 0, (state.text == null) ? 30 : state.text.size * scale + 20, - (this.textarea.style.textAlign == 'left') ? 120 : 40); -}; - -/** - * Function: getEditorBounds - * - * Returns the <mxRectangle> that defines the bounds of the editor. - */ -mxCellEditor.prototype.getEditorBounds = function(state) -{ - var isEdge = this.graph.getModel().isEdge(state.cell); - var scale = this.graph.getView().scale; - var minSize = this.getMinimumSize(state); - var minWidth = minSize.width; - var minHeight = minSize.height; - - var spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 2) * scale; - var spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0)) * scale + spacing; - var spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0)) * scale + spacing; - var spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0)) * scale + spacing; - var spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0)) * scale + spacing; - - var result = new mxRectangle(state.x, state.y, - Math.max(minWidth, state.width - spacingLeft - spacingRight), - Math.max(minHeight, state.height - spacingTop - spacingBottom)); - - if (isEdge) - { - result.x = state.absoluteOffset.x; - result.y = state.absoluteOffset.y; - - if (state.text != null && state.text.boundingBox != null) - { - // Workaround for label containing just spaces in which case - // the bounding box location contains negative numbers - if (state.text.boundingBox.x > 0) - { - result.x = state.text.boundingBox.x; - } - - if (state.text.boundingBox.y > 0) - { - result.y = state.text.boundingBox.y; - } - } - } - else if (state.text != null && state.text.boundingBox != null) - { - result.x = Math.min(result.x, state.text.boundingBox.x); - result.y = Math.min(result.y, state.text.boundingBox.y); - } - - result.x += spacingLeft; - result.y += spacingTop; - - if (state.text != null && state.text.boundingBox != null) - { - if (!isEdge) - { - result.width = Math.max(result.width, state.text.boundingBox.width); - result.height = Math.max(result.height, state.text.boundingBox.height); - } - else - { - result.width = Math.max(minWidth, state.text.boundingBox.width); - result.height = Math.max(minHeight, state.text.boundingBox.height); - } - } - - // Applies the horizontal and vertical label positions - if (this.graph.getModel().isVertex(state.cell)) - { - var horizontal = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); - - if (horizontal == mxConstants.ALIGN_LEFT) - { - result.x -= state.width; - } - else if (horizontal == mxConstants.ALIGN_RIGHT) - { - result.x += state.width; - } - - var vertical = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); - - if (vertical == mxConstants.ALIGN_TOP) - { - result.y -= state.height; - } - else if (vertical == mxConstants.ALIGN_BOTTOM) - { - result.y += state.height; - } - } - - return result; -}; - -/** - * Function: getEmptyLabelText - * - * Returns the initial label value to be used of the label of the given - * cell is empty. This label is displayed and cleared on the first keystroke. - * This implementation returns <emptyLabelText>. - * - * Parameters: - * - * cell - <mxCell> for which a text for an empty editing box should be - * returned. - */ -mxCellEditor.prototype.getEmptyLabelText = function (cell) -{ - return this.emptyLabelText; -}; - -/** - * Function: getEditingCell - * - * Returns the cell that is currently being edited or null if no cell is - * being edited. - */ -mxCellEditor.prototype.getEditingCell = function () -{ - return this.editingCell; -}; - -/** - * Function: destroy - * - * Destroys the editor and removes all associated resources. - */ -mxCellEditor.prototype.destroy = function () -{ - if (this.textarea != null) - { - mxEvent.release(this.textarea); - - if (this.textarea.parentNode != null) - { - this.textarea.parentNode.removeChild(this.textarea); - } - - this.textarea = null; - } -}; diff --git a/src/js/view/mxCellOverlay.js b/src/js/view/mxCellOverlay.js deleted file mode 100644 index 316e2c4..0000000 --- a/src/js/view/mxCellOverlay.js +++ /dev/null @@ -1,233 +0,0 @@ -/** - * $Id: mxCellOverlay.js,v 1.18 2012-12-06 15:58:44 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellOverlay - * - * Extends <mxEventSource> to implement a graph overlay, represented by an icon - * and a tooltip. Overlays can handle and fire <click> events and are added to - * the graph using <mxGraph.addCellOverlay>, and removed using - * <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays. - * The <mxGraph.getCellOverlays> function returns the array of overlays for a given - * cell in a graph. If multiple overlays exist for the same cell, then - * <getBounds> should be overridden in at least one of the overlays. - * - * Overlays appear on top of all cells in a special layer. If this is not - * desirable, then the image must be rendered as part of the shape or label of - * the cell instead. - * - * Example: - * - * The following adds a new overlays for a given vertex and selects the cell - * if the overlay is clicked. - * - * (code) - * var overlay = new mxCellOverlay(img, html); - * graph.addCellOverlay(vertex, overlay); - * overlay.addListener(mxEvent.CLICK, function(sender, evt) - * { - * var cell = evt.getProperty('cell'); - * graph.setSelectionCell(cell); - * }); - * (end) - * - * For cell overlays to be printed use <mxPrintPreview.printOverlays>. - * - * Event: mxEvent.CLICK - * - * Fires when the user clicks on the overlay. The <code>event</code> property - * contains the corresponding mouse event and the <code>cell</code> property - * contains the cell. For touch devices this is fired if the element receives - * a touchend event. - * - * Constructor: mxCellOverlay - * - * Constructs a new overlay using the given image and tooltip. - * - * Parameters: - * - * image - <mxImage> that represents the icon to be displayed. - * tooltip - Optional string that specifies the tooltip. - * align - Optional horizontal alignment for the overlay. Possible - * values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT> - * (default). - * verticalAlign - Vertical alignment for the overlay. Possible - * values are <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM> - * (default). - */ -function mxCellOverlay(image, tooltip, align, verticalAlign, offset, cursor) -{ - this.image = image; - this.tooltip = tooltip; - this.align = (align != null) ? align : this.align; - this.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign; - this.offset = (offset != null) ? offset : new mxPoint(); - this.cursor = (cursor != null) ? cursor : 'help'; -}; - -/** - * Extends mxEventSource. - */ -mxCellOverlay.prototype = new mxEventSource(); -mxCellOverlay.prototype.constructor = mxCellOverlay; - -/** - * Variable: image - * - * Holds the <mxImage> to be used as the icon. - */ -mxCellOverlay.prototype.image = null; - -/** - * Variable: tooltip - * - * Holds the optional string to be used as the tooltip. - */ -mxCellOverlay.prototype.tooltip = null; - -/** - * Variable: align - * - * Holds the horizontal alignment for the overlay. Default is - * <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the - * center of the edge. - */ -mxCellOverlay.prototype.align = mxConstants.ALIGN_RIGHT; - -/** - * Variable: verticalAlign - * - * Holds the vertical alignment for the overlay. Default is - * <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the - * center of the edge. - */ -mxCellOverlay.prototype.verticalAlign = mxConstants.ALIGN_BOTTOM; - -/** - * Variable: offset - * - * Holds the offset as an <mxPoint>. The offset will be scaled according to the - * current scale. - */ -mxCellOverlay.prototype.offset = null; - -/** - * Variable: cursor - * - * Holds the cursor for the overlay. Default is 'help'. - */ -mxCellOverlay.prototype.cursor = null; - -/** - * Variable: defaultOverlap - * - * Defines the overlapping for the overlay, that is, the proportional distance - * from the origin to the point defined by the alignment. Default is 0.5. - */ -mxCellOverlay.prototype.defaultOverlap = 0.5; - -/** - * Function: getBounds - * - * Returns the bounds of the overlay for the given <mxCellState> as an - * <mxRectangle>. This should be overridden when using multiple overlays - * per cell so that the overlays do not overlap. - * - * The following example will place the overlay along an edge (where - * x=[-1..1] from the start to the end of the edge and y is the - * orthogonal offset in px). - * - * (code) - * overlay.getBounds = function(state) - * { - * var bounds = mxCellOverlay.prototype.getBounds.apply(this, arguments); - * - * if (state.view.graph.getModel().isEdge(state.cell)) - * { - * var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true}); - * - * bounds.x = pt.x - bounds.width / 2; - * bounds.y = pt.y - bounds.height / 2; - * } - * - * return bounds; - * }; - * (end) - * - * Parameters: - * - * state - <mxCellState> that represents the current state of the - * associated cell. - */ -mxCellOverlay.prototype.getBounds = function(state) -{ - var isEdge = state.view.graph.getModel().isEdge(state.cell); - var s = state.view.scale; - var pt = null; - - var w = this.image.width; - var h = this.image.height; - - if (isEdge) - { - var pts = state.absolutePoints; - - if (pts.length % 2 == 1) - { - pt = pts[Math.floor(pts.length / 2)]; - } - else - { - var idx = pts.length / 2; - var p0 = pts[idx-1]; - var p1 = pts[idx]; - pt = new mxPoint(p0.x + (p1.x - p0.x) / 2, - p0.y + (p1.y - p0.y) / 2); - } - } - else - { - pt = new mxPoint(); - - if (this.align == mxConstants.ALIGN_LEFT) - { - pt.x = state.x; - } - else if (this.align == mxConstants.ALIGN_CENTER) - { - pt.x = state.x + state.width / 2; - } - else - { - pt.x = state.x + state.width; - } - - if (this.verticalAlign == mxConstants.ALIGN_TOP) - { - pt.y = state.y; - } - else if (this.verticalAlign == mxConstants.ALIGN_MIDDLE) - { - pt.y = state.y + state.height / 2; - } - else - { - pt.y = state.y + state.height; - } - } - - return new mxRectangle(pt.x - (w * this.defaultOverlap - this.offset.x) * s, - pt.y - (h * this.defaultOverlap - this.offset.y) * s, w * s, h * s); -}; - -/** - * Function: toString - * - * Returns the textual representation of the overlay to be used as the - * tooltip. This implementation returns <tooltip>. - */ -mxCellOverlay.prototype.toString = function() -{ - return this.tooltip; -}; diff --git a/src/js/view/mxCellRenderer.js b/src/js/view/mxCellRenderer.js deleted file mode 100644 index 6b506ad..0000000 --- a/src/js/view/mxCellRenderer.js +++ /dev/null @@ -1,1480 +0,0 @@ -/** - * $Id: mxCellRenderer.js,v 1.189 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellRenderer - * - * Renders cells into a document object model. The <defaultShapes> is a global - * map of shapename, constructor pairs that is used in all instances. You can - * get a list of all available shape names using the following code. - * - * In general the cell renderer is in charge of creating, redrawing and - * destroying the shape and label associated with a cell state, as well as - * some other graphical objects, namely controls and overlays. The shape - * hieararchy in the display (ie. the hierarchy in which the DOM nodes - * appear in the document) does not reflect the cell hierarchy. The shapes - * are a (flat) sequence of shapes and labels inside the draw pane of the - * graph view, with some exceptions, namely the HTML labels being placed - * directly inside the graph container for certain browsers. - * - * (code) - * mxLog.show(); - * for (var i in mxCellRenderer.prototype.defaultShapes) - * { - * mxLog.debug(i); - * } - * (end) - * - * Constructor: mxCellRenderer - * - * Constructs a new cell renderer with the following built-in shapes: - * arrow, rectangle, ellipse, rhombus, image, line, label, cylinder, - * swimlane, connector, actor and cloud. - */ -function mxCellRenderer() -{ - this.shapes = mxUtils.clone(this.defaultShapes); -}; - -/** - * Variable: shapes - * - * Array that maps from shape names to shape constructors. All entries - * in <defaultShapes> are added to this array. - */ -mxCellRenderer.prototype.shapes = null; - -/** - * Variable: defaultEdgeShape - * - * Defines the default shape for edges. Default is <mxConnector>. - */ -mxCellRenderer.prototype.defaultEdgeShape = mxConnector; - -/** - * Variable: defaultVertexShape - * - * Defines the default shape for vertices. Default is <mxRectangleShape>. - */ -mxCellRenderer.prototype.defaultVertexShape = mxRectangleShape; - -/** - * Variable: defaultShapes - * - * Static array that contains the globally registered shapes which are - * known to all instances of this class. For adding instance-specific - * shapes you should use <registerShape> on the instance. For adding - * a shape to this array you can use the following code: - * - * (code) - * mxCellRenderer.prototype.defaultShapes['myshape'] = myShape; - * (end) - * - * Where 'myshape' is the key under which the shape is to be registered - * and myShape is the name of the constructor function. - */ -mxCellRenderer.prototype.defaultShapes = new Object(); - -// Adds default shapes into the default shapes array -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ARROW] = mxArrow; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RECTANGLE] = mxRectangleShape; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ELLIPSE] = mxEllipse; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_DOUBLE_ELLIPSE] = mxDoubleEllipse; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RHOMBUS] = mxRhombus; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_IMAGE] = mxImageShape; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LINE] = mxLine; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LABEL] = mxLabel; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CYLINDER] = mxCylinder; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_SWIMLANE] = mxSwimlane; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CONNECTOR] = mxConnector; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ACTOR] = mxActor; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CLOUD] = mxCloud; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_TRIANGLE] = mxTriangle; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_HEXAGON] = mxHexagon; - -/** - * Function: registerShape - * - * Registers the given constructor under the specified key in this instance - * of the renderer. - * - * Example: - * - * (code) - * this.registerShape(mxConstants.SHAPE_RECTANGLE, mxRectangleShape); - * (end) - * - * Parameters: - * - * key - String representing the shape name. - * shape - Constructor of the <mxShape> subclass. - */ -mxCellRenderer.prototype.registerShape = function(key, shape) -{ - this.shapes[key] = shape; -}; - -/** - * Function: initialize - * - * Initializes the display for the given cell state. This is required once - * after the cell state has been created. This is invoked in - * mxGraphView.createState. - * - * Parameters: - * - * state - <mxCellState> for which the display should be initialized. - * rendering - Optional boolean that specifies if the cell should actually - * be initialized for any given DOM node. If this is false then init - * will not be called on the shape. - */ -mxCellRenderer.prototype.initialize = function(state, rendering) -{ - var model = state.view.graph.getModel(); - - if (state.view.graph.container != null && state.shape == null && - state.cell != state.view.currentRoot && - (model.isVertex(state.cell) || model.isEdge(state.cell))) - { - this.createShape(state); - - if (state.shape != null && (rendering == null || rendering)) - { - this.initializeShape(state); - - // Maintains the model order in the DOM - if (state.view.graph.ordered || model.isEdge(state.cell)) - { - //state.orderChanged = true; - state.invalidOrder = true; - } - else if (state.view.graph.keepEdgesInForeground && this.firstEdge != null) - { - if (this.firstEdge.parentNode == state.shape.node.parentNode) - { - this.insertState(state, this.firstEdge); - } - else - { - this.firstEdge = null; - } - } - - state.shape.scale = state.view.scale; - - this.createCellOverlays(state); - this.installListeners(state); - } - } -}; - -/** - * Function: initializeShape - * - * Initializes the shape in the given state by calling its init method with - * the correct container. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be initialized. - */ -mxCellRenderer.prototype.initializeShape = function(state) -{ - state.shape.init(state.view.getDrawPane()); -}; - -/** - * Returns the previous state that has a shape inside the given parent. - */ -mxCellRenderer.prototype.getPreviousStateInContainer = function(state, container) -{ - var result = null; - var graph = state.view.graph; - var model = graph.getModel(); - var child = state.cell; - var p = model.getParent(child); - - while (p != null && result == null) - { - result = this.findPreviousStateInContainer(graph, p, child, container); - child = p; - p = model.getParent(child); - } - - return result; -}; - -/** - * Returns the previous state that has a shape inside the given parent. - */ -mxCellRenderer.prototype.findPreviousStateInContainer = function(graph, cell, stop, container) -{ - // Recurse first - var result = null; - var model = graph.getModel(); - - if (stop != null) - { - var start = cell.getIndex(stop); - - for (var i = start - 1; i >= 0 && result == null; i--) - { - result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container); - } - } - else - { - var childCount = model.getChildCount(cell); - - for (var i = childCount - 1; i >= 0 && result == null; i--) - { - result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container); - } - } - - if (result == null) - { - result = graph.view.getState(cell); - - if (result != null && (result.shape == null || result.shape.node == null || - result.shape.node.parentNode != container)) - { - result = null; - } - } - - return result; -}; - -/** - * Function: order - * - * Orders the DOM node of the shape for the given state according to the - * position of the corresponding cell in the graph model. - * - * Parameters: - * - * state - <mxCellState> whose shape's DOM node should be ordered. - */ -mxCellRenderer.prototype.order = function(state) -{ - var container = state.shape.node.parentNode; - var previous = this.getPreviousStateInContainer(state, container); - var nextNode = container.firstChild; - - if (previous != null) - { - nextNode = previous.shape.node; - - if (previous.text != null && previous.text.node != null && - previous.text.node.parentNode == container) - { - nextNode = previous.text.node; - } - - nextNode = nextNode.nextSibling; - } - - this.insertState(state, nextNode); -}; - -/** - * Function: orderEdge - * - * Orders the DOM node of the shape for the given edge's state according to - * the <mxGraph.keepEdgesInBackground> and <mxGraph.keepEdgesInBackground> - * rules. - * - * Parameters: - * - * state - <mxCellState> whose shape's DOM node should be ordered. - */ -mxCellRenderer.prototype.orderEdge = function(state) -{ - var view = state.view; - var model = view.graph.getModel(); - - // Moves edges to the foreground/background - if (view.graph.keepEdgesInForeground) - { - if (this.firstEdge == null || this.firstEdge.parentNode == null || - this.firstEdge.parentNode != state.shape.node.parentNode) - { - this.firstEdge = state.shape.node; - } - } - else if (view.graph.keepEdgesInBackground) - { - var node = state.shape.node; - var parent = node.parentNode; - - // Keeps the DOM node in front of its parent - var pcell = model.getParent(state.cell); - var pstate = view.getState(pcell); - - if (pstate != null && pstate.shape != null && pstate.shape.node != null) - { - var child = pstate.shape.node.nextSibling; - - if (child != null && child != node) - { - this.insertState(state, child); - } - } - else - { - var child = parent.firstChild; - - if (child != null && child != node) - { - this.insertState(state, child); - } - } - } -}; - -/** - * Function: insertState - * - * Inserts the given state before the given node into its parent. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be created. - */ -mxCellRenderer.prototype.insertState = function(state, nextNode) -{ - state.shape.node.parentNode.insertBefore(state.shape.node, nextNode); - - if (state.text != null && state.text.node != null && - state.text.node.parentNode == state.shape.node.parentNode) - { - state.shape.node.parentNode.insertBefore(state.text.node, state.shape.node.nextSibling); - } -}; - -/** - * Function: createShape - * - * Creates the shape for the given cell state. The shape is configured - * using <configureShape>. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be created. - */ -mxCellRenderer.prototype.createShape = function(state) -{ - if (state.style != null) - { - // Checks if there is a stencil for the name and creates - // a shape instance for the stencil if one exists - var key = state.style[mxConstants.STYLE_SHAPE]; - var stencil = mxStencilRegistry.getStencil(key); - - if (stencil != null) - { - state.shape = new mxStencilShape(stencil); - } - else - { - var ctor = this.getShapeConstructor(state); - state.shape = new ctor(); - } - - // Sets the initial bounds and points (will be updated in redraw) - state.shape.points = state.absolutePoints; - state.shape.bounds = new mxRectangle( - state.x, state.y, state.width, state.height); - state.shape.dialect = state.view.graph.dialect; - - this.configureShape(state); - } -}; - -/** - * Function: getShapeConstructor - * - * Returns the constructor to be used for creating the shape. - */ -mxCellRenderer.prototype.getShapeConstructor = function(state) -{ - var key = state.style[mxConstants.STYLE_SHAPE]; - var ctor = (key != null) ? this.shapes[key] : null; - - if (ctor == null) - { - ctor = (state.view.graph.getModel().isEdge(state.cell)) ? - this.defaultEdgeShape : this.defaultVertexShape; - } - - return ctor; -}; - -/** - * Function: configureShape - * - * Configures the shape for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be configured. - */ -mxCellRenderer.prototype.configureShape = function(state) -{ - state.shape.apply(state); - var image = state.view.graph.getImage(state); - - if (image != null) - { - state.shape.image = image; - } - - var indicator = state.view.graph.getIndicatorColor(state); - var key = state.view.graph.getIndicatorShape(state); - var ctor = (key != null) ? this.shapes[key] : null; - - // Configures the indicator shape or image - if (indicator != null) - { - state.shape.indicatorShape = ctor; - state.shape.indicatorColor = indicator; - state.shape.indicatorGradientColor = - state.view.graph.getIndicatorGradientColor(state); - state.shape.indicatorDirection = - state.style[mxConstants.STYLE_INDICATOR_DIRECTION]; - } - else - { - var indicator = state.view.graph.getIndicatorImage(state); - - if (indicator != null) - { - state.shape.indicatorImage = indicator; - } - } - - this.postConfigureShape(state); -}; - -/** - * Function: postConfigureShape - * - * Replaces any reserved words used for attributes, eg. inherit, - * indicated or swimlane for colors in the shape for the given state. - * This implementation resolves these keywords on the fill, stroke - * and gradient color keys. - */ -mxCellRenderer.prototype.postConfigureShape = function(state) -{ - if (state.shape != null) - { - this.resolveColor(state, 'indicatorColor', mxConstants.STYLE_FILLCOLOR); - this.resolveColor(state, 'indicatorGradientColor', mxConstants.STYLE_GRADIENTCOLOR); - this.resolveColor(state, 'fill', mxConstants.STYLE_FILLCOLOR); - this.resolveColor(state, 'stroke', mxConstants.STYLE_STROKECOLOR); - this.resolveColor(state, 'gradient', mxConstants.STYLE_GRADIENTCOLOR); - } -}; - -/** - * Function: resolveColor - * - * Resolves special keywords 'inherit', 'indicated' and 'swimlane' and sets - * the respective color on the shape. - */ -mxCellRenderer.prototype.resolveColor = function(state, field, key) -{ - var value = state.shape[field]; - var graph = state.view.graph; - var referenced = null; - - if (value == 'inherit') - { - referenced = graph.model.getParent(state.cell); - } - else if (value == 'swimlane') - { - if (graph.model.getTerminal(state.cell, false) != null) - { - referenced = graph.model.getTerminal(state.cell, false); - } - else - { - referenced = state.cell; - } - - referenced = graph.getSwimlane(referenced); - key = graph.swimlaneIndicatorColorAttribute; - } - else if (value == 'indicated') - { - state.shape[field] = state.shape.indicatorColor; - } - - if (referenced != null) - { - var rstate = graph.getView().getState(referenced); - state.shape[field] = null; - - if (rstate != null) - { - if (rstate.shape != null && field != 'indicatorColor') - { - state.shape[field] = rstate.shape[field]; - } - else - { - state.shape[field] = rstate.style[key]; - } - } - } -}; - -/** - * Function: getLabelValue - * - * Returns the value to be used for the label. - * - * Parameters: - * - * state - <mxCellState> for which the label should be created. - */ -mxCellRenderer.prototype.getLabelValue = function(state) -{ - var graph = state.view.graph; - var value = graph.getLabel(state.cell); - - if (!graph.isHtmlLabel(state.cell) && !mxUtils.isNode(value) && - graph.dialect != mxConstants.DIALECT_SVG && value != null) - { - value = mxUtils.htmlEntities(value, false); - } - - return value; -}; - -/** - * Function: createLabel - * - * Creates the label for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the label should be created. - */ -mxCellRenderer.prototype.createLabel = function(state, value) -{ - var graph = state.view.graph; - var isEdge = graph.getModel().isEdge(state.cell); - - if (state.style[mxConstants.STYLE_FONTSIZE] > 0 || - state.style[mxConstants.STYLE_FONTSIZE] == null) - { - // Avoids using DOM node for empty labels - var isForceHtml = (graph.isHtmlLabel(state.cell) || - (value != null && mxUtils.isNode(value))) && - graph.dialect == mxConstants.DIALECT_SVG; - - state.text = new mxText(value, new mxRectangle(), - (state.style[mxConstants.STYLE_ALIGN] || - mxConstants.ALIGN_CENTER), - graph.getVerticalAlign(state), - state.style[mxConstants.STYLE_FONTCOLOR], - state.style[mxConstants.STYLE_FONTFAMILY], - state.style[mxConstants.STYLE_FONTSIZE], - state.style[mxConstants.STYLE_FONTSTYLE], - state.style[mxConstants.STYLE_SPACING], - state.style[mxConstants.STYLE_SPACING_TOP], - state.style[mxConstants.STYLE_SPACING_RIGHT], - state.style[mxConstants.STYLE_SPACING_BOTTOM], - state.style[mxConstants.STYLE_SPACING_LEFT], - state.style[mxConstants.STYLE_HORIZONTAL], - state.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR], - state.style[mxConstants.STYLE_LABEL_BORDERCOLOR], - graph.isWrapping(state.cell) && graph.isHtmlLabel(state.cell), - graph.isLabelClipped(state.cell), - state.style[mxConstants.STYLE_OVERFLOW], - state.style[mxConstants.STYLE_LABEL_PADDING]); - state.text.opacity = state.style[mxConstants.STYLE_TEXT_OPACITY]; - - state.text.dialect = (isForceHtml) ? - mxConstants.DIALECT_STRICTHTML : - state.view.graph.dialect; - this.initializeLabel(state); - - // Workaround for touch devices routing all events for a mouse - // gesture (down, move, up) via the initial DOM node. IE is even - // worse in that it redirects the event via the initial DOM node - // but the event source is the node under the mouse, so we need - // to check if this is the case and force getCellAt for the - // subsequent mouseMoves and the final mouseUp. - var forceGetCell = false; - - var getState = function(evt) - { - var result = state; - - if (mxClient.IS_TOUCH || forceGetCell) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(graph.container, x, y); - result = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return result; - }; - - // TODO: Add handling for gestures - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(state.text.node, md, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, state)); - forceGetCell = graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG'; - } - }) - ); - - mxEvent.addListener(state.text.node, mm, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, getState(evt))); - } - }) - ); - - mxEvent.addListener(state.text.node, mu, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, getState(evt))); - forceGetCell = false; - } - }) - ); - - mxEvent.addListener(state.text.node, 'dblclick', - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.dblClick(evt, state.cell); - mxEvent.consume(evt); - } - }) - ); - } -}; - -/** - * Function: initializeLabel - * - * Initiailzes the label with a suitable container. - * - * Parameters: - * - * state - <mxCellState> whose label should be initialized. - */ -mxCellRenderer.prototype.initializeLabel = function(state) -{ - var graph = state.view.graph; - - if (state.text.dialect != mxConstants.DIALECT_SVG) - { - // Adds the text to the container if the dialect is not SVG and we - // have an SVG-based browser which doesn't support foreignObjects - if (mxClient.IS_SVG && mxClient.NO_FO) - { - state.text.init(graph.container); - } - else if (mxUtils.isVml(state.view.getDrawPane())) - { - if (state.shape.label != null) - { - state.text.init(state.shape.label); - } - else - { - state.text.init(state.shape.node); - } - } - } - - if (state.text.node == null) - { - state.text.init(state.view.getDrawPane()); - - if (state.shape != null && state.text != null) - { - state.shape.node.parentNode.insertBefore( - state.text.node, state.shape.node.nextSibling); - } - } -}; - -/** - * Function: createCellOverlays - * - * Creates the actual shape for showing the overlay for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the overlay should be created. - */ -mxCellRenderer.prototype.createCellOverlays = function(state) -{ - var graph = state.view.graph; - var overlays = graph.getCellOverlays(state.cell); - var dict = null; - - if (overlays != null) - { - dict = new mxDictionary(); - - for (var i = 0; i < overlays.length; i++) - { - var shape = (state.overlays != null) ? state.overlays.remove(overlays[i]) : null; - - if (shape == null) - { - var tmp = new mxImageShape(new mxRectangle(), - overlays[i].image.src); - tmp.dialect = state.view.graph.dialect; - tmp.preserveImageAspect = false; - tmp.overlay = overlays[i]; - this.initializeOverlay(state, tmp); - this.installCellOverlayListeners(state, overlays[i], tmp); - - if (overlays[i].cursor != null) - { - tmp.node.style.cursor = overlays[i].cursor; - } - - dict.put(overlays[i], tmp); - } - else - { - dict.put(overlays[i], shape); - } - } - } - - // Removes unused - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - shape.destroy(); - }); - } - - state.overlays = dict; -}; - -/** - * Function: initializeOverlay - * - * Initializes the given overlay. - * - * Parameters: - * - * state - <mxCellState> for which the overlay should be created. - * overlay - <mxImageShape> that represents the overlay. - */ -mxCellRenderer.prototype.initializeOverlay = function(state, overlay) -{ - overlay.init(state.view.getOverlayPane()); -}; - -/** - * Function: installOverlayListeners - * - * Installs the listeners for the given <mxCellState>, <mxCellOverlay> and - * <mxShape> that represents the overlay. - */ -mxCellRenderer.prototype.installCellOverlayListeners = function(state, overlay, shape) -{ - var graph = state.view.graph; - - mxEvent.addListener(shape.node, 'click', function (evt) - { - if (graph.isEditing()) - { - graph.stopEditing(!graph.isInvokesStopCellEditing()); - } - - overlay.fireEvent(new mxEventObject(mxEvent.CLICK, - 'event', evt, 'cell', state.cell)); - }); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - - mxEvent.addListener(shape.node, md, function (evt) - { - mxEvent.consume(evt); - }); - - mxEvent.addListener(shape.node, mm, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, state)); - }); - - if (mxClient.IS_TOUCH) - { - mxEvent.addListener(shape.node, 'touchend', function (evt) - { - overlay.fireEvent(new mxEventObject(mxEvent.CLICK, - 'event', evt, 'cell', state.cell)); - }); - } -}; - -/** - * Function: createControl - * - * Creates the control for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the control should be created. - */ -mxCellRenderer.prototype.createControl = function(state) -{ - var graph = state.view.graph; - var image = graph.getFoldingImage(state); - - if (graph.foldingEnabled && image != null) - { - if (state.control == null) - { - var b = new mxRectangle(0, 0, image.width, image.height); - state.control = new mxImageShape(b, image.src); - state.control.dialect = graph.dialect; - state.control.preserveImageAspect = false; - - this.initControl(state, state.control, true, function (evt) - { - if (graph.isEnabled()) - { - var collapse = !graph.isCellCollapsed(state.cell); - graph.foldCells(collapse, false, [state.cell]); - mxEvent.consume(evt); - } - }); - } - } - else if (state.control != null) - { - state.control.destroy(); - state.control = null; - } -}; - -/** - * Function: initControl - * - * Initializes the given control and returns the corresponding DOM node. - * - * Parameters: - * - * state - <mxCellState> for which the control should be initialized. - * control - <mxShape> to be initialized. - * handleEvents - Boolean indicating if mousedown and mousemove should fire events via the graph. - * clickHandler - Optional function to implement clicks on the control. - */ -mxCellRenderer.prototype.initControl = function(state, control, handleEvents, clickHandler) -{ - var graph = state.view.graph; - - // In the special case where the label is in HTML and the display is SVG the image - // should go into the graph container directly in order to be clickable. Otherwise - // it is obscured by the HTML label that overlaps the cell. - var isForceHtml = graph.isHtmlLabel(state.cell) && - mxClient.NO_FO && - graph.dialect == mxConstants.DIALECT_SVG; - - if (isForceHtml) - { - control.dialect = mxConstants.DIALECT_PREFERHTML; - control.init(graph.container); - control.node.style.zIndex = 1; - } - else - { - control.init(state.view.getOverlayPane()); - } - - var node = control.innerNode || control.node; - - if (clickHandler) - { - if (graph.isEnabled()) - { - node.style.cursor = 'pointer'; - } - - mxEvent.addListener(node, 'click', clickHandler); - } - - if (handleEvents) - { - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - - mxEvent.addListener(node, md, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state)); - mxEvent.consume(evt); - }); - - mxEvent.addListener(node, mm, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, state)); - }); - } - - return node; -}; - -/** - * Function: isShapeEvent - * - * Returns true if the event is for the shape of the given state. This - * implementation always returns true. - * - * Parameters: - * - * state - <mxCellState> whose shape fired the event. - * evt - Mouse event which was fired. - */ -mxCellRenderer.prototype.isShapeEvent = function(state, evt) -{ - return true; -}; - -/** - * Function: isLabelEvent - * - * Returns true if the event is for the label of the given state. This - * implementation always returns true. - * - * Parameters: - * - * state - <mxCellState> whose label fired the event. - * evt - Mouse event which was fired. - */ -mxCellRenderer.prototype.isLabelEvent = function(state, evt) -{ - return true; -}; - -/** - * Function: installListeners - * - * Installs the event listeners for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the event listeners should be isntalled. - */ -mxCellRenderer.prototype.installListeners = function(state) -{ - var graph = state.view.graph; - - // Receives events from transparent backgrounds - if (graph.dialect == mxConstants.DIALECT_SVG) - { - var events = 'all'; - - // Disabled fill-events on non-filled edges - if (graph.getModel().isEdge(state.cell) && state.shape.stroke != null && - (state.shape.fill == null || state.shape.fill == mxConstants.NONE)) - { - events = 'visibleStroke'; - } - - // Specifies the event-processing on the shape - if (state.shape.innerNode != null) - { - state.shape.innerNode.setAttribute('pointer-events', events); - } - else - { - state.shape.node.setAttribute('pointer-events', events); - } - } - - // Workaround for touch devices routing all events for a mouse - // gesture (down, move, up) via the initial DOM node. Same for - // HTML images in all IE versions (VML images are working). - var getState = function(evt) - { - var result = state; - - if ((graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG') || mxClient.IS_TOUCH) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(graph.container, x, y); - result = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return result; - }; - - // Experimental support for two-finger pinch to resize cells - var gestureInProgress = false; - - mxEvent.addListener(state.shape.node, 'gesturestart', - mxUtils.bind(this, function(evt) - { - // FIXME: Breaks encapsulation to reset the double - // tap event handling when gestures take place - graph.lastTouchTime = 0; - - gestureInProgress = true; - mxEvent.consume(evt); - }) - ); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(state.shape.node, md, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - // Redirects events from the "event-transparent" region of - // a swimlane to the graph. This is only required in HTML, - // SVG and VML do not fire mouse events on transparent - // backgrounds. - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : state)); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - mxEvent.addListener(state.shape.node, mm, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : getState(evt))); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - mxEvent.addListener(state.shape.node, mu, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : getState(evt))); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - // Experimental handling for gestures. Double-tap handling is implemented - // in mxGraph.fireMouseEvent. - var dc = (mxClient.IS_TOUCH) ? 'gestureend' : 'dblclick'; - - mxEvent.addListener(state.shape.node, dc, - mxUtils.bind(this, function(evt) - { - gestureInProgress = false; - - if (dc == 'gestureend') - { - // FIXME: Breaks encapsulation to reset the double - // tap event handling when gestures take place - graph.lastTouchTime = 0; - - if (graph.gestureEnabled) - { - graph.handleGesture(state, evt); - mxEvent.consume(evt); - } - } - else if (this.isShapeEvent(state, evt)) - { - graph.dblClick(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : state.cell); - mxEvent.consume(evt); - } - }) - ); -}; - -/** - * Function: redrawLabel - * - * Redraws the label for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose label should be redrawn. - */ -mxCellRenderer.prototype.redrawLabel = function(state) -{ - var value = this.getLabelValue(state); - - // FIXME: Add label always if HTML label and NO_FO - if (state.text == null && value != null && (mxUtils.isNode(value) || value.length > 0)) - { - this.createLabel(state, value); - } - else if (state.text != null && (value == null || value.length == 0)) - { - state.text.destroy(); - state.text = null; - } - - if (state.text != null) - { - var graph = state.view.graph; - var wrapping = graph.isWrapping(state.cell); - var clipping = graph.isLabelClipped(state.cell); - var bounds = this.getLabelBounds(state); - - if (state.text.value != value || state.text.isWrapping != wrapping || - state.text.isClipping != clipping || state.text.scale != state.view.scale || - !state.text.bounds.equals(bounds)) - { - state.text.value = value; - state.text.bounds = bounds; - state.text.scale = this.getTextScale(state); - state.text.isWrapping = wrapping; - state.text.isClipping = clipping; - - state.text.redraw(); - } - } -}; - -/** - * Function: getTextScale - * - * Returns the scaling used for the label of the given state - * - * Parameters: - * - * state - <mxCellState> whose label scale should be returned. - */ -mxCellRenderer.prototype.getTextScale = function(state) -{ - return state.view.scale; -}; - -/** - * Function: getLabelBounds - * - * Returns the bounds to be used to draw the label of the given state. - * - * Parameters: - * - * state - <mxCellState> whose label bounds should be returned. - */ -mxCellRenderer.prototype.getLabelBounds = function(state) -{ - var graph = state.view.graph; - var isEdge = graph.getModel().isEdge(state.cell); - var bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y); - - if (!isEdge) - { - bounds.x += state.x; - bounds.y += state.y; - - // Minimum of 1 fixes alignment bug in HTML labels - bounds.width = Math.max(1, state.width); - bounds.height = Math.max(1, state.height); - - if (graph.isSwimlane(state.cell)) - { - var scale = graph.view.scale; - var size = graph.getStartSize(state.cell); - - if (size.width > 0) - { - bounds.width = size.width * scale; - } - else if (size.height > 0) - { - bounds.height = size.height * scale; - } - } - } - - return bounds; -}; - -/** - * Function: redrawCellOverlays - * - * Redraws the overlays for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose overlays should be redrawn. - */ -mxCellRenderer.prototype.redrawCellOverlays = function(state) -{ - this.createCellOverlays(state); - - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - var bounds = shape.overlay.getBounds(state); - - if (shape.bounds == null || shape.scale != state.view.scale || - !shape.bounds.equals(bounds)) - { - shape.bounds = bounds; - shape.scale = state.view.scale; - shape.redraw(); - } - }); - } -}; - -/** - * Function: redrawControl - * - * Redraws the control for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose control should be redrawn. - */ -mxCellRenderer.prototype.redrawControl = function(state) -{ - if (state.control != null) - { - var bounds = this.getControlBounds(state); - var s = state.view.scale; - - if (state.control.scale != s || !state.control.bounds.equals(bounds)) - { - state.control.bounds = bounds; - state.control.scale = s; - state.control.redraw(); - } - } -}; - -/** - * Function: getControlBounds - * - * Returns the bounds to be used to draw the control (folding icon) of the - * given state. - */ -mxCellRenderer.prototype.getControlBounds = function(state) -{ - if (state.control != null) - { - var oldScale = state.control.scale; - var w = state.control.bounds.width / oldScale; - var h = state.control.bounds.height / oldScale; - var s = state.view.scale; - - return (state.view.graph.getModel().isEdge(state.cell)) ? - new mxRectangle(state.x + state.width / 2 - w / 2 * s, - state.y + state.height / 2 - h / 2 * s, w * s, h * s) - : new mxRectangle(state.x + w / 2 * s, - state.y + h / 2 * s, w * s, h * s); - } - - return null; -}; - -/** - * Function: redraw - * - * Updates the bounds or points and scale of the shapes for the given cell - * state. This is called in mxGraphView.validatePoints as the last step of - * updating all cells. - * - * Parameters: - * - * state - <mxCellState> for which the shapes should be updated. - * force - Optional boolean that specifies if the cell should be reconfiured - * and redrawn without any additional checks. - * rendering - Optional boolean that specifies if the cell should actually - * be drawn into the DOM. If this is false then redraw and/or reconfigure - * will not be called on the shape. - */ -mxCellRenderer.prototype.redraw = function(state, force, rendering) -{ - if (state.shape != null) - { - var model = state.view.graph.getModel(); - var isEdge = model.isEdge(state.cell); - reconfigure = (force != null) ? force : false; - - // Handles changes of the collapse icon - this.createControl(state); - - // Handles changes to the order in the DOM - if (state.orderChanged || state.invalidOrder) - { - if (state.view.graph.ordered) - { - this.order(state); - } - else - { - // Assert state.cell is edge - this.orderEdge(state); - } - - // Required to update inherited styles - reconfigure = state.orderChanged; - } - - delete state.invalidOrder; - delete state.orderChanged; - - // Checks if the style in the state is different from the style - // in the shape and re-applies the style if required - if (!reconfigure && !mxUtils.equalEntries(state.shape.style, state.style)) - { - reconfigure = true; - } - - // Reconfiures the shape after an order or style change - if (reconfigure) - { - this.configureShape(state); - state.shape.reconfigure(); - } - - // Redraws the cell if required - if (force || state.shape.bounds == null || state.shape.scale != state.view.scale || - !state.shape.bounds.equals(state) || - !mxUtils.equalPoints(state.shape.points, state.absolutePoints)) - { - // FIXME: Move indicator color update into shape.redraw -// var indicator = state.view.graph.getIndicatorColor(state); -// if (indicator != null) -// { -// state.shape.indicatorColor = indicator; -// } - - if (state.absolutePoints != null) - { - state.shape.points = state.absolutePoints.slice(); - } - else - { - state.shape.points = null; - } - - state.shape.bounds = new mxRectangle( - state.x, state.y, state.width, state.height); - state.shape.scale = state.view.scale; - - if (rendering == null || rendering) - { - state.shape.redraw(); - } - else - { - state.shape.updateBoundingBox(); - } - } - - // Updates the text label, overlays and control - if (rendering == null || rendering) - { - this.redrawLabel(state); - this.redrawCellOverlays(state); - this.redrawControl(state); - } - } -}; - -/** - * Function: destroy - * - * Destroys the shapes associated with the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the shapes should be destroyed. - */ -mxCellRenderer.prototype.destroy = function(state) -{ - if (state.shape != null) - { - if (state.text != null) - { - state.text.destroy(); - state.text = null; - } - - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - shape.destroy(); - }); - - state.overlays = null; - } - - if (state.control != null) - { - state.control.destroy(); - state.control = null; - } - - state.shape.destroy(); - state.shape = null; - } -}; diff --git a/src/js/view/mxCellState.js b/src/js/view/mxCellState.js deleted file mode 100644 index 7e7a3b0..0000000 --- a/src/js/view/mxCellState.js +++ /dev/null @@ -1,375 +0,0 @@ -/** - * $Id: mxCellState.js,v 1.42 2012-03-19 10:47:08 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellState - * - * Represents the current state of a cell in a given <mxGraphView>. - * - * For edges, the edge label position is stored in <absoluteOffset>. - * - * The size for oversize labels can be retrieved using the boundingBox property - * of the <text> field as shown below. - * - * (code) - * var bbox = (state.text != null) ? state.text.boundingBox : null; - * (end) - * - * Constructor: mxCellState - * - * Constructs a new object that represents the current state of the given - * cell in the specified view. - * - * Parameters: - * - * view - <mxGraphView> that contains the state. - * cell - <mxCell> that this state represents. - * style - Array of key, value pairs that constitute the style. - */ -function mxCellState(view, cell, style) -{ - this.view = view; - this.cell = cell; - this.style = style; - - this.origin = new mxPoint(); - this.absoluteOffset = new mxPoint(); -}; - -/** - * Extends mxRectangle. - */ -mxCellState.prototype = new mxRectangle(); -mxCellState.prototype.constructor = mxCellState; - -/** - * Variable: view - * - * Reference to the enclosing <mxGraphView>. - */ -mxCellState.prototype.view = null; - -/** - * Variable: cell - * - * Reference to the <mxCell> that is represented by this state. - */ -mxCellState.prototype.cell = null; - -/** - * Variable: style - * - * Contains an array of key, value pairs that represent the style of the - * cell. - */ -mxCellState.prototype.style = null; - -/** - * Variable: invalid - * - * Specifies if the state is invalid. Default is true. - */ -mxCellState.prototype.invalid = true; - -/** - * Variable: invalidOrder - * - * Specifies if the cell has an invalid order. For internal use. Default is - * false. - */ -mxCellState.prototype.invalidOrder = false; - -/** - * Variable: orderChanged - * - * Specifies if the cell has changed order and the display needs to be - * updated. - */ -mxCellState.prototype.orderChanged = false; - -/** - * Variable: origin - * - * <mxPoint> that holds the origin for all child cells. Default is a new - * empty <mxPoint>. - */ -mxCellState.prototype.origin = null; - -/** - * Variable: absolutePoints - * - * Holds an array of <mxPoints> that represent the absolute points of an - * edge. - */ -mxCellState.prototype.absolutePoints = null; - -/** - * Variable: absoluteOffset - * - * <mxPoint> that holds the absolute offset. For edges, this is the - * absolute coordinates of the label position. For vertices, this is the - * offset of the label relative to the top, left corner of the vertex. - */ -mxCellState.prototype.absoluteOffset = null; - -/** - * Variable: visibleSourceState - * - * Caches the visible source terminal state. - */ -mxCellState.prototype.visibleSourceState = null; - -/** - * Variable: visibleTargetState - * - * Caches the visible target terminal state. - */ -mxCellState.prototype.visibleTargetState = null; - -/** - * Variable: terminalDistance - * - * Caches the distance between the end points for an edge. - */ -mxCellState.prototype.terminalDistance = 0; - -/** - * Variable: length - * - * Caches the length of an edge. - */ -mxCellState.prototype.length = 0; - -/** - * Variable: segments - * - * Array of numbers that represent the cached length of each segment of the - * edge. - */ -mxCellState.prototype.segments = null; - -/** - * Variable: shape - * - * Holds the <mxShape> that represents the cell graphically. - */ -mxCellState.prototype.shape = null; - -/** - * Variable: text - * - * Holds the <mxText> that represents the label of the cell. Thi smay be - * null if the cell has no label. - */ -mxCellState.prototype.text = null; - -/** - * Function: getPerimeterBounds - * - * Returns the <mxRectangle> that should be used as the perimeter of the - * cell. - * - * Parameters: - * - * border - Optional border to be added around the perimeter bounds. - * bounds - Optional <mxRectangle> to be used as the initial bounds. - */ -mxCellState.prototype.getPerimeterBounds = function (border, bounds) -{ - border = border || 0; - bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height); - - if (this.shape != null && this.shape.stencil != null) - { - var aspect = this.shape.stencil.computeAspect(this, bounds, null); - - bounds.x = aspect.x; - bounds.y = aspect.y; - bounds.width = this.shape.stencil.w0 * aspect.width; - bounds.height = this.shape.stencil.h0 * aspect.height; - } - - if (border != 0) - { - bounds.grow(border); - } - - return bounds; -}; - -/** - * Function: setAbsoluteTerminalPoint - * - * Sets the first or last point in <absolutePoints> depending on isSource. - * - * Parameters: - * - * point - <mxPoint> that represents the terminal point. - * isSource - Boolean that specifies if the first or last point should - * be assigned. - */ -mxCellState.prototype.setAbsoluteTerminalPoint = function (point, isSource) -{ - if (isSource) - { - if (this.absolutePoints == null) - { - this.absolutePoints = []; - } - - if (this.absolutePoints.length == 0) - { - this.absolutePoints.push(point); - } - else - { - this.absolutePoints[0] = point; - } - } - else - { - if (this.absolutePoints == null) - { - this.absolutePoints = []; - this.absolutePoints.push(null); - this.absolutePoints.push(point); - } - else if (this.absolutePoints.length == 1) - { - this.absolutePoints.push(point); - } - else - { - this.absolutePoints[this.absolutePoints.length - 1] = point; - } - } -}; - -/** - * Function: setCursor - * - * Sets the given cursor on the shape and text shape. - */ -mxCellState.prototype.setCursor = function (cursor) -{ - if (this.shape != null) - { - this.shape.setCursor(cursor); - } - - if (this.text != null) - { - this.text.setCursor(cursor); - } -}; - -/** - * Function: getVisibleTerminal - * - * Returns the visible source or target terminal cell. - * - * Parameters: - * - * source - Boolean that specifies if the source or target cell should be - * returned. - */ -mxCellState.prototype.getVisibleTerminal = function (source) -{ - var tmp = this.getVisibleTerminalState(source); - - return (tmp != null) ? tmp.cell : null; -}; - -/** - * Function: getVisibleTerminalState - * - * Returns the visible source or target terminal state. - * - * Parameters: - * - * source - Boolean that specifies if the source or target state should be - * returned. - */ -mxCellState.prototype.getVisibleTerminalState = function (source) -{ - return (source) ? this.visibleSourceState : this.visibleTargetState; -}; - -/** - * Function: setVisibleTerminalState - * - * Sets the visible source or target terminal state. - * - * Parameters: - * - * terminalState - <mxCellState> that represents the terminal. - * source - Boolean that specifies if the source or target state should be set. - */ -mxCellState.prototype.setVisibleTerminalState = function (terminalState, source) -{ - if (source) - { - this.visibleSourceState = terminalState; - } - else - { - this.visibleTargetState = terminalState; - } -}; - -/** - * Destructor: destroy - * - * Destroys the state and all associated resources. - */ -mxCellState.prototype.destroy = function () -{ - this.view.graph.cellRenderer.destroy(this); -}; - -/** - * Function: clone - * - * Returns a clone of this <mxPoint>. - */ -mxCellState.prototype.clone = function() -{ - var clone = new mxCellState(this.view, this.cell, this.style); - - // Clones the absolute points - if (this.absolutePoints != null) - { - clone.absolutePoints = []; - - for (var i = 0; i < this.absolutePoints.length; i++) - { - clone.absolutePoints[i] = this.absolutePoints[i].clone(); - } - } - - if (this.origin != null) - { - clone.origin = this.origin.clone(); - } - - if (this.absoluteOffset != null) - { - clone.absoluteOffset = this.absoluteOffset.clone(); - } - - if (this.boundingBox != null) - { - clone.boundingBox = this.boundingBox.clone(); - } - - clone.terminalDistance = this.terminalDistance; - clone.segments = this.segments; - clone.length = this.length; - clone.x = this.x; - clone.y = this.y; - clone.width = this.width; - clone.height = this.height; - - return clone; -}; diff --git a/src/js/view/mxCellStatePreview.js b/src/js/view/mxCellStatePreview.js deleted file mode 100644 index b853748..0000000 --- a/src/js/view/mxCellStatePreview.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * $Id: mxCellStatePreview.js,v 1.6 2012-10-26 07:19:11 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxCellStatePreview - * - * Implements a live preview for moving cells. - * - * Constructor: mxCellStatePreview - * - * Constructs a move preview for the given graph. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxCellStatePreview(graph) -{ - this.graph = graph; - this.deltas = new Object(); -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellStatePreview.prototype.graph = null; - -/** - * Variable: deltas - * - * Reference to the enclosing <mxGraph>. - */ -mxCellStatePreview.prototype.deltas = null; - -/** - * Variable: count - * - * Contains the number of entries in the map. - */ -mxCellStatePreview.prototype.count = 0; - -/** - * Function: isEmpty - * - * Returns true if this contains no entries. - */ -mxCellStatePreview.prototype.isEmpty = function() -{ - return this.count == 0; -}; - -/** - * Function: moveState - */ -mxCellStatePreview.prototype.moveState = function(state, dx, dy, add, includeEdges) -{ - add = (add != null) ? add : true; - includeEdges = (includeEdges != null) ? includeEdges : true; - var id = mxCellPath.create(state.cell); - var delta = this.deltas[id]; - - if (delta == null) - { - delta = new mxPoint(dx, dy); - this.deltas[id] = delta; - this.count++; - } - else - { - if (add) - { - delta.X += dx; - delta.Y += dy; - } - else - { - delta.X = dx; - delta.Y = dy; - } - } - - if (includeEdges) - { - this.addEdges(state); - } - - return delta; -}; - -/** - * Function: show - */ -mxCellStatePreview.prototype.show = function(visitor) -{ - var model = this.graph.getModel(); - var root = model.getRoot(); - - // Translates the states in step - for (var id in this.deltas) - { - var cell = mxCellPath.resolve(root, id); - var state = this.graph.view.getState(cell); - var delta = this.deltas[id]; - var parentState = this.graph.view.getState( - model.getParent(cell)); - this.translateState(parentState, state, delta.x, delta.y); - } - - // Revalidates the states in step - for (var id in this.deltas) - { - var cell = mxCellPath.resolve(root, id); - var state = this.graph.view.getState(cell); - var delta = this.deltas[id]; - var parentState = this.graph.view.getState( - model.getParent(cell)); - this.revalidateState(parentState, state, delta.x, delta.y, visitor); - } -}; - -/** - * Function: translateState - */ -mxCellStatePreview.prototype.translateState = function(parentState, state, dx, dy) -{ - if (state != null) - { - var model = this.graph.getModel(); - - if (model.isVertex(state.cell)) - { - // LATER: Use hashtable to store initial state bounds - state.invalid = true; - this.graph.view.validateBounds(parentState, state.cell); - var geo = model.getGeometry(state.cell); - var id = mxCellPath.create(state.cell); - - // Moves selection cells and non-relative vertices in - // the first phase so that edge terminal points will - // be updated in the second phase - if ((dx != 0 || dy != 0) && geo != null && - (!geo.relative || this.deltas[id] != null)) - { - state.x += dx; - state.y += dy; - } - } - - var childCount = model.getChildCount(state.cell); - - for (var i = 0; i < childCount; i++) - { - this.translateState(state, this.graph.view.getState( - model.getChildAt(state.cell, i)), dx, dy); - } - } -}; - -/** - * Function: revalidateState - */ -mxCellStatePreview.prototype.revalidateState = function(parentState, state, dx, dy, visitor) -{ - if (state != null) - { - // Updates the edge terminal points and restores the - // (relative) positions of any (relative) children - state.invalid = true; - this.graph.view.validatePoints(parentState, state.cell); - - // Moves selection vertices which are relative - var id = mxCellPath.create(state.cell); - var model = this.graph.getModel(); - var geo = this.graph.getCellGeometry(state.cell); - - if ((dx != 0 || dy != 0) && geo != null && geo.relative && - model.isVertex(state.cell) && (parentState == null || - model.isVertex(parentState.cell) || this.deltas[id] != null)) - { - state.x += dx; - state.y += dy; - - this.graph.cellRenderer.redraw(state); - } - - // Invokes the visitor on the given state - if (visitor != null) - { - visitor(state); - } - - var childCount = model.getChildCount(state.cell); - - for (var i = 0; i < childCount; i++) - { - this.revalidateState(state, this.graph.view.getState(model.getChildAt( - state.cell, i)), dx, dy, visitor); - } - } -}; - -/** - * Function: addEdges - */ -mxCellStatePreview.prototype.addEdges = function(state) -{ - var model = this.graph.getModel(); - var edgeCount = model.getEdgeCount(state.cell); - - for (var i = 0; i < edgeCount; i++) - { - var s = this.graph.view.getState(model.getEdgeAt(state.cell, i)); - - if (s != null) - { - this.moveState(s, 0, 0); - } - } -}; diff --git a/src/js/view/mxConnectionConstraint.js b/src/js/view/mxConnectionConstraint.js deleted file mode 100644 index 70f457f..0000000 --- a/src/js/view/mxConnectionConstraint.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * $Id: mxConnectionConstraint.js,v 1.2 2010-04-29 09:33:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxConnectionConstraint - * - * Defines an object that contains the constraints about how to connect one - * side of an edge to its terminal. - * - * Constructor: mxConnectionConstraint - * - * Constructs a new connection constraint for the given point and boolean - * arguments. - * - * Parameters: - * - * point - Optional <mxPoint> that specifies the fixed location of the point - * in relative coordinates. Default is null. - * perimeter - Optional boolean that specifies if the fixed point should be - * projected onto the perimeter of the terminal. Default is true. - */ -function mxConnectionConstraint(point, perimeter) -{ - this.point = point; - this.perimeter = (perimeter != null) ? perimeter : true; -}; - -/** - * Variable: point - * - * <mxPoint> that specifies the fixed location of the connection point. - */ -mxConnectionConstraint.prototype.point = null; - -/** - * Variable: perimeter - * - * Boolean that specifies if the point should be projected onto the perimeter - * of the terminal. - */ -mxConnectionConstraint.prototype.perimeter = null; diff --git a/src/js/view/mxEdgeStyle.js b/src/js/view/mxEdgeStyle.js deleted file mode 100644 index 41493d6..0000000 --- a/src/js/view/mxEdgeStyle.js +++ /dev/null @@ -1,1302 +0,0 @@ -/** - * $Id: mxEdgeStyle.js,v 1.68 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxEdgeStyle = -{ - /** - * Class: mxEdgeStyle - * - * Provides various edge styles to be used as the values for - * <mxConstants.STYLE_EDGE> in a cell style. - * - * Example: - * - * (code) - * var style = stylesheet.getDefaultEdgeStyle(); - * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - * (end) - * - * Sets the default edge style to <ElbowConnector>. - * - * Custom edge style: - * - * To write a custom edge style, a function must be added to the mxEdgeStyle - * object as follows: - * - * (code) - * mxEdgeStyle.MyStyle = function(state, source, target, points, result) - * { - * if (source != null && target != null) - * { - * var pt = new mxPoint(target.getCenterX(), source.getCenterY()); - * - * if (mxUtils.contains(source, pt.x, pt.y)) - * { - * pt.y = source.y + source.height; - * } - * - * result.push(pt); - * } - * }; - * (end) - * - * In the above example, a right angle is created using a point on the - * horizontal center of the target vertex and the vertical center of the source - * vertex. The code checks if that point intersects the source vertex and makes - * the edge straight if it does. The point is then added into the result array, - * which acts as the return value of the function. - * - * The new edge style should then be registered in the <mxStyleRegistry> as follows: - * (code) - * mxStyleRegistry.putValue('myEdgeStyle', mxEdgeStyle.MyStyle); - * (end) - * - * The custom edge style above can now be used in a specific edge as follows: - * - * (code) - * model.setStyle(edge, 'edgeStyle=myEdgeStyle'); - * (end) - * - * Note that the key of the <mxStyleRegistry> entry for the function should - * be used in string values, unless <mxGraphView.allowEval> is true, in - * which case you can also use mxEdgeStyle.MyStyle for the value in the - * cell style above. - * - * Or it can be used for all edges in the graph as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultEdgeStyle(); - * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.MyStyle; - * (end) - * - * Note that the object can be used directly when programmatically setting - * the value, but the key in the <mxStyleRegistry> should be used when - * setting the value via a key, value pair in a cell style. - * - * Function: EntityRelation - * - * Implements an entity relation style for edges (as used in database - * schema diagrams). At the time the function is called, the result - * array contains a placeholder (null) for the first absolute point, - * that is, the point where the edge and source terminal are connected. - * The implementation of the style then adds all intermediate waypoints - * except for the last point, that is, the connection point between the - * edge and the target terminal. The first ant the last point in the - * result array are then replaced with mxPoints that take into account - * the terminal's perimeter and next point on the edge. - * - * Parameters: - * - * state - <mxCellState> that represents the edge to be updated. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - * points - List of relative control points. - * result - Array of <mxPoints> that represent the actual points of the - * edge. - */ - EntityRelation: function (state, source, target, points, result) - { - var view = state.view; - var graph = view.graph; - var segment = mxUtils.getValue(state.style, - mxConstants.STYLE_SEGMENT, - mxConstants.ENTITY_SEGMENT) * view.scale; - - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - var isSourceLeft = false; - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - else if (source != null) - { - var constraint = mxUtils.getPortConstraints(source, state, true, mxConstants.DIRECTION_MASK_NONE); - - if (constraint != mxConstants.DIRECTION_MASK_NONE) - { - isSourceLeft = constraint == mxConstants.DIRECTION_MASK_WEST; - } - else - { - var sourceGeometry = graph.getCellGeometry(source.cell); - - if (sourceGeometry.relative) - { - isSourceLeft = sourceGeometry.x <= 0.5; - } - else if (target != null) - { - isSourceLeft = target.x + target.width < source.x; - } - } - } - else - { - return; - } - - var isTargetLeft = true; - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - else if (target != null) - { - var constraint = mxUtils.getPortConstraints(target, state, false, mxConstants.DIRECTION_MASK_NONE); - - if (constraint != mxConstants.DIRECTION_MASK_NONE) - { - isTargetLeft = constraint == mxConstants.DIRECTION_MASK_WEST; - } - else - { - var targetGeometry = graph.getCellGeometry(target.cell); - - if (targetGeometry.relative) - { - isTargetLeft = targetGeometry.x <= 0.5; - } - else if (source != null) - { - isTargetLeft = source.x + source.width < target.x; - } - } - } - - if (source != null && target != null) - { - var x0 = (isSourceLeft) ? source.x : source.x + source.width; - var y0 = view.getRoutingCenterY(source); - - var xe = (isTargetLeft) ? target.x : target.x + target.width; - var ye = view.getRoutingCenterY(target); - - var seg = segment; - - var dx = (isSourceLeft) ? -seg : seg; - var dep = new mxPoint(x0 + dx, y0); - - dx = (isTargetLeft) ? -seg : seg; - var arr = new mxPoint(xe + dx, ye); - - // Adds intermediate points if both go out on same side - if (isSourceLeft == isTargetLeft) - { - var x = (isSourceLeft) ? - Math.min(x0, xe)-segment : - Math.max(x0, xe)+segment; - - result.push(new mxPoint(x, y0)); - result.push(new mxPoint(x, ye)); - } - else if ((dep.x < arr.x) == isSourceLeft) - { - var midY = y0 + (ye - y0) / 2; - - result.push(dep); - result.push(new mxPoint(dep.x, midY)); - result.push(new mxPoint(arr.x, midY)); - result.push(arr); - } - else - { - result.push(dep); - result.push(arr); - } - } - }, - - /** - * Function: Loop - * - * Implements a self-reference, aka. loop. - */ - Loop: function (state, source, target, points, result) - { - if (source != null) - { - var view = state.view; - var graph = view.graph; - var pt = (points != null && points.length > 0) ? points[0] : null; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - - if (mxUtils.contains(source, pt.x, pt.y)) - { - pt = null; - } - } - - var x = 0; - var dx = 0; - var y = 0; - var dy = 0; - - var seg = mxUtils.getValue(state.style, mxConstants.STYLE_SEGMENT, - graph.gridSize) * view.scale; - var dir = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION, - mxConstants.DIRECTION_WEST); - - if (dir == mxConstants.DIRECTION_NORTH || - dir == mxConstants.DIRECTION_SOUTH) - { - x = view.getRoutingCenterX(source); - dx = seg; - } - else - { - y = view.getRoutingCenterY(source); - dy = seg; - } - - if (pt == null || - pt.x < source.x || - pt.x > source.x + source.width) - { - if (pt != null) - { - x = pt.x; - dy = Math.max(Math.abs(y - pt.y), dy); - } - else - { - if (dir == mxConstants.DIRECTION_NORTH) - { - y = source.y - 2 * dx; - } - else if (dir == mxConstants.DIRECTION_SOUTH) - { - y = source.y + source.height + 2 * dx; - } - else if (dir == mxConstants.DIRECTION_EAST) - { - x = source.x - 2 * dy; - } - else - { - x = source.x + source.width + 2 * dy; - } - } - } - else if (pt != null) - { - x = view.getRoutingCenterX(source); - dx = Math.max(Math.abs(x - pt.x), dy); - y = pt.y; - dy = 0; - } - - result.push(new mxPoint(x - dx, y - dy)); - result.push(new mxPoint(x + dx, y + dy)); - } - }, - - /** - * Function: ElbowConnector - * - * Uses either <SideToSide> or <TopToBottom> depending on the horizontal - * flag in the cell style. <SideToSide> is used if horizontal is true or - * unspecified. See <EntityRelation> for a description of the - * parameters. - */ - ElbowConnector: function (state, source, target, points, result) - { - var pt = (points != null && points.length > 0) ? points[0] : null; - - var vertical = false; - var horizontal = false; - - if (source != null && target != null) - { - if (pt != null) - { - var left = Math.min(source.x, target.x); - var right = Math.max(source.x + source.width, - target.x + target.width); - - var top = Math.min(source.y, target.y); - var bottom = Math.max(source.y + source.height, - target.y + target.height); - - pt = state.view.transformControlPoint(state, pt); - - vertical = pt.y < top || pt.y > bottom; - horizontal = pt.x < left || pt.x > right; - } - else - { - var left = Math.max(source.x, target.x); - var right = Math.min(source.x + source.width, - target.x + target.width); - - vertical = left == right; - - if (!vertical) - { - var top = Math.max(source.y, target.y); - var bottom = Math.min(source.y + source.height, - target.y + target.height); - - horizontal = top == bottom; - } - } - } - - if (!horizontal && (vertical || - state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) - { - mxEdgeStyle.TopToBottom(state, source, target, points, result); - } - else - { - mxEdgeStyle.SideToSide(state, source, target, points, result); - } - }, - - /** - * Function: SideToSide - * - * Implements a vertical elbow edge. See <EntityRelation> for a description - * of the parameters. - */ - SideToSide: function (state, source, target, points, result) - { - var view = state.view; - var pt = (points != null && points.length > 0) ? points[0] : null; - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - } - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - - if (source != null && target != null) - { - var l = Math.max(source.x, target.x); - var r = Math.min(source.x + source.width, - target.x + target.width); - - var x = (pt != null) ? pt.x : r + (l - r) / 2; - - var y1 = view.getRoutingCenterY(source); - var y2 = view.getRoutingCenterY(target); - - if (pt != null) - { - if (pt.y >= source.y && pt.y <= source.y + source.height) - { - y1 = pt.y; - } - - if (pt.y >= target.y && pt.y <= target.y + target.height) - { - y2 = pt.y; - } - } - - if (!mxUtils.contains(target, x, y1) && - !mxUtils.contains(source, x, y1)) - { - result.push(new mxPoint(x, y1)); - } - - if (!mxUtils.contains(target, x, y2) && - !mxUtils.contains(source, x, y2)) - { - result.push(new mxPoint(x, y2)); - } - - if (result.length == 1) - { - if (pt != null) - { - if (!mxUtils.contains(target, x, pt.y) && - !mxUtils.contains(source, x, pt.y)) - { - result.push(new mxPoint(x, pt.y)); - } - } - else - { - var t = Math.max(source.y, target.y); - var b = Math.min(source.y + source.height, - target.y + target.height); - - result.push(new mxPoint(x, t + (b - t) / 2)); - } - } - } - }, - - /** - * Function: TopToBottom - * - * Implements a horizontal elbow edge. See <EntityRelation> for a - * description of the parameters. - */ - TopToBottom: function(state, source, target, points, result) - { - var view = state.view; - var pt = (points != null && points.length > 0) ? points[0] : null; - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - } - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - - if (source != null && target != null) - { - var t = Math.max(source.y, target.y); - var b = Math.min(source.y + source.height, - target.y + target.height); - - var x = view.getRoutingCenterX(source); - - if (pt != null && - pt.x >= source.x && - pt.x <= source.x + source.width) - { - x = pt.x; - } - - var y = (pt != null) ? pt.y : b + (t - b) / 2; - - if (!mxUtils.contains(target, x, y) && - !mxUtils.contains(source, x, y)) - { - result.push(new mxPoint(x, y)); - } - - if (pt != null && - pt.x >= target.x && - pt.x <= target.x + target.width) - { - x = pt.x; - } - else - { - x = view.getRoutingCenterX(target); - } - - if (!mxUtils.contains(target, x, y) && - !mxUtils.contains(source, x, y)) - { - result.push(new mxPoint(x, y)); - } - - if (result.length == 1) - { - if (pt != null && result.length == 1) - { - if (!mxUtils.contains(target, pt.x, y) && - !mxUtils.contains(source, pt.x, y)) - { - result.push(new mxPoint(pt.x, y)); - } - } - else - { - var l = Math.max(source.x, target.x); - var r = Math.min(source.x + source.width, - target.x + target.width); - - result.push(new mxPoint(l + (r - l) / 2, y)); - } - } - } - }, - - /** - * Function: SegmentConnector - * - * Implements an orthogonal edge style. Use <mxEdgeSegmentHandler> - * as an interactive handler for this style. - */ - SegmentConnector: function(state, source, target, hints, result) - { - // Creates array of all way- and terminalpoints - var pts = state.absolutePoints; - var horizontal = true; - var hint = null; - - // Adds the first point - var pt = pts[0]; - - if (pt == null && source != null) - { - pt = new mxPoint(state.view.getRoutingCenterX(source), state.view.getRoutingCenterY(source)); - } - else if (pt != null) - { - pt = pt.clone(); - } - - var lastInx = pts.length - 1; - - // Adds the waypoints - if (hints != null && hints.length > 0) - { - hint = state.view.transformControlPoint(state, hints[0]); - - var currentTerm = source; - var currentPt = pts[0]; - var hozChan = false; - var vertChan = false; - var currentHint = hint; - var hintsLen = hints.length; - - for (var i = 0; i < 2; i++) - { - var fixedVertAlign = currentPt != null && currentPt.x == currentHint.x; - var fixedHozAlign = currentPt != null && currentPt.y == currentHint.y; - var inHozChan = currentTerm != null && (currentHint.y >= currentTerm.y && - currentHint.y <= currentTerm.y + currentTerm.height); - var inVertChan = currentTerm != null && (currentHint.x >= currentTerm.x && - currentHint.x <= currentTerm.x + currentTerm.width); - - hozChan = fixedHozAlign || (currentPt == null && inHozChan); - vertChan = fixedVertAlign || (currentPt == null && inVertChan); - - if (currentPt != null && (!fixedHozAlign && !fixedVertAlign) && (inHozChan || inVertChan)) - { - horizontal = inHozChan ? false : true; - break; - } - - if (vertChan || hozChan) - { - horizontal = hozChan; - - if (i == 1) - { - // Work back from target end - horizontal = hints.length % 2 == 0 ? hozChan : vertChan; - } - - break; - } - - currentTerm = target; - currentPt = pts[lastInx]; - currentHint = state.view.transformControlPoint(state, hints[hintsLen - 1]); - } - - if (horizontal && ((pts[0] != null && pts[0].y != hint.y) || - (pts[0] == null && source != null && - (hint.y < source.y || hint.y > source.y + source.height)))) - { - result.push(new mxPoint(pt.x, hint.y)); - } - else if (!horizontal && ((pts[0] != null && pts[0].x != hint.x) || - (pts[0] == null && source != null && - (hint.x < source.x || hint.x > source.x + source.width)))) - { - result.push(new mxPoint(hint.x, pt.y)); - } - - if (horizontal) - { - pt.y = hint.y; - } - else - { - pt.x = hint.x; - } - - for (var i = 0; i < hints.length; i++) - { - horizontal = !horizontal; - hint = state.view.transformControlPoint(state, hints[i]); - -// mxLog.show(); -// mxLog.debug('hint', i, hint.x, hint.y); - - if (horizontal) - { - pt.y = hint.y; - } - else - { - pt.x = hint.x; - } - - result.push(pt.clone()); - } - } - else - { - hint = pt; - // FIXME: First click in connect preview toggles orientation - horizontal = true; - } - - // Adds the last point - pt = pts[lastInx]; - - if (pt == null && target != null) - { - pt = new mxPoint(state.view.getRoutingCenterX(target), state.view.getRoutingCenterY(target)); - } - - if (horizontal && ((pts[lastInx] != null && pts[lastInx].y != hint.y) || - (pts[lastInx] == null && target != null && - (hint.y < target.y || hint.y > target.y + target.height)))) - { - result.push(new mxPoint(pt.x, hint.y)); - } - else if (!horizontal && ((pts[lastInx] != null && pts[lastInx].x != hint.x) || - (pts[lastInx] == null && target != null && - (hint.x < target.x || hint.x > target.x + target.width)))) - { - result.push(new mxPoint(hint.x, pt.y)); - } - - // Removes bends inside the source terminal for floating ports - if (pts[0] == null && source != null) - { - while (result.length > 1 && mxUtils.contains(source, result[1].x, result[1].y)) - { - result = result.splice(1, 1); - } - } - - // Removes bends inside the target terminal - if (pts[lastInx] == null && target != null) - { - while (result.length > 1 && mxUtils.contains(target, result[result.length - 1].x, result[result.length - 1].y)) - { - result = result.splice(result.length - 1, 1); - } - } - - }, - - orthBuffer: 10, - - dirVectors: [ [ -1, 0 ], - [ 0, -1 ], [ 1, 0 ], [ 0, 1 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ] ], - - wayPoints1: [ [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], - [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0] ], - - routePatterns: [ - [ [ 513, 2308, 2081, 2562 ], [ 513, 1090, 514, 2184, 2114, 2561 ], - [ 513, 1090, 514, 2564, 2184, 2562 ], - [ 513, 2308, 2561, 1090, 514, 2568, 2308 ] ], - [ [ 514, 1057, 513, 2308, 2081, 2562 ], [ 514, 2184, 2114, 2561 ], - [ 514, 2184, 2562, 1057, 513, 2564, 2184 ], - [ 514, 1057, 513, 2568, 2308, 2561 ] ], - [ [ 1090, 514, 1057, 513, 2308, 2081, 2562 ], [ 2114, 2561 ], - [ 1090, 2562, 1057, 513, 2564, 2184 ], - [ 1090, 514, 1057, 513, 2308, 2561, 2568 ] ], - [ [ 2081, 2562 ], [ 1057, 513, 1090, 514, 2184, 2114, 2561 ], - [ 1057, 513, 1090, 514, 2184, 2562, 2564 ], - [ 1057, 2561, 1090, 514, 2568, 2308 ] ] ], - - inlineRoutePatterns: [ - [ null, [ 2114, 2568 ], null, null ], - [ null, [ 514, 2081, 2114, 2568 ] , null, null ], - [ null, [ 2114, 2561 ], null, null ], - [ [ 2081, 2562 ], [ 1057, 2114, 2568 ], - [ 2184, 2562 ], - null ] ], - vertexSeperations: [], - - limits: [ - [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ], - - LEFT_MASK: 32, - - TOP_MASK: 64, - - RIGHT_MASK: 128, - - BOTTOM_MASK: 256, - - LEFT: 1, - - TOP: 2, - - RIGHT: 4, - - BOTTOM: 8, - - // TODO remove magic numbers - SIDE_MASK: 480, - //mxEdgeStyle.LEFT_MASK | mxEdgeStyle.TOP_MASK | mxEdgeStyle.RIGHT_MASK - //| mxEdgeStyle.BOTTOM_MASK, - - CENTER_MASK: 512, - - SOURCE_MASK: 1024, - - TARGET_MASK: 2048, - - VERTEX_MASK: 3072, - // mxEdgeStyle.SOURCE_MASK | mxEdgeStyle.TARGET_MASK, - - /** - * Function: OrthConnector - * - * Implements a local orthogonal router between the given - * cells. - */ - OrthConnector: function(state, source, target, points, result) - { - var graph = state.view.graph; - var sourceEdge = source == null ? false : graph.getModel().isEdge(source.cell); - var targetEdge = target == null ? false : graph.getModel().isEdge(target.cell); - - if ((points != null && points.length > 0) || (sourceEdge) || (targetEdge)) - { - mxEdgeStyle.SegmentConnector(state, source, target, points, result); - return; - } - - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - var sourceX = source != null ? source.x : p0.x; - var sourceY = source != null ? source.y : p0.y; - var sourceWidth = source != null ? source.width : 1; - var sourceHeight = source != null ? source.height : 1; - - var targetX = target != null ? target.x : pe.x; - var targetY = target != null ? target.y : pe.y; - var targetWidth = target != null ? target.width : 1; - var targetHeight = target != null ? target.height : 1; - - var scaledOrthBuffer = state.view.scale * mxEdgeStyle.orthBuffer; - // Determine the side(s) of the source and target vertices - // that the edge may connect to - // portConstraint [source, target] - var portConstraint = [mxConstants.DIRECTION_MASK_ALL, mxConstants.DIRECTION_MASK_ALL]; - - if (source != null) - { - portConstraint[0] = mxUtils.getPortConstraints(source, state, true, - mxConstants.DIRECTION_MASK_ALL); - } - - if (target != null) - { - portConstraint[1] = mxUtils.getPortConstraints(target, state, false, - mxConstants.DIRECTION_MASK_ALL); - } - - var dir = [0, 0] ; - - // Work out which faces of the vertices present against each other - // in a way that would allow a 3-segment connection if port constraints - // permitted. - // geo -> [source, target] [x, y, width, height] - var geo = [ [sourceX, sourceY, sourceWidth, sourceHeight] , - [targetX, targetY, targetWidth, targetHeight] ]; - - for (var i = 0; i < 2; i++) - { - mxEdgeStyle.limits[i][1] = geo[i][0] - scaledOrthBuffer; - mxEdgeStyle.limits[i][2] = geo[i][1] - scaledOrthBuffer; - mxEdgeStyle.limits[i][4] = geo[i][0] + geo[i][2] + scaledOrthBuffer; - mxEdgeStyle.limits[i][8] = geo[i][1] + geo[i][3] + scaledOrthBuffer; - } - - // Work out which quad the target is in - var sourceCenX = geo[0][0] + geo[0][2] / 2.0; - var sourceCenY = geo[0][1] + geo[0][3] / 2.0; - var targetCenX = geo[1][0] + geo[1][2] / 2.0; - var targetCenY = geo[1][1] + geo[1][3] / 2.0; - - var dx = sourceCenX - targetCenX; - var dy = sourceCenY - targetCenY; - - var quad = 0; - - if (dx < 0) - { - if (dy < 0) - { - quad = 2; - } - else - { - quad = 1; - } - } - else - { - if (dy <= 0) - { - quad = 3; - - // Special case on x = 0 and negative y - if (dx == 0) - { - quad = 2; - } - } - } - - // Check for connection constraints - var currentTerm = null; - - if (source != null) - { - currentTerm = p0; - } - - var constraint = [ [0.5, 0.5] , [0.5, 0.5] ]; - - for (var i = 0; i < 2; i++) - { - if (currentTerm != null) - { - constraint[i][0] = (currentTerm.x - geo[i][0]) / geo[i][2]; - - if (constraint[i][0] < 0.01) - { - dir[i] = mxConstants.DIRECTION_MASK_WEST; - } - else if (constraint[i][0] > 0.99) - { - dir[i] = mxConstants.DIRECTION_MASK_EAST; - } - - constraint[i][1] = (currentTerm.y - geo[i][1]) / geo[i][3]; - - if (constraint[i][1] < 0.01) - { - dir[i] = mxConstants.DIRECTION_MASK_NORTH; - } - else if (constraint[i][1] > 0.99) - { - dir[i] = mxConstants.DIRECTION_MASK_SOUTH; - } - } - - currentTerm = null; - - if (target != null) - { - currentTerm = pe; - } - } - - var sourceTopDist = geo[0][1] - (geo[1][1] + geo[1][3]); - var sourceLeftDist = geo[0][0] - (geo[1][0] + geo[1][2]); - var sourceBottomDist = geo[1][1] - (geo[0][1] + geo[0][3]); - var sourceRightDist = geo[1][0] - (geo[0][0] + geo[0][2]); - - mxEdgeStyle.vertexSeperations[1] = Math.max( - sourceLeftDist - 2 * scaledOrthBuffer, 0); - mxEdgeStyle.vertexSeperations[2] = Math.max(sourceTopDist - 2 * scaledOrthBuffer, - 0); - mxEdgeStyle.vertexSeperations[4] = Math.max(sourceBottomDist - 2 - * scaledOrthBuffer, 0); - mxEdgeStyle.vertexSeperations[3] = Math.max(sourceRightDist - 2 - * scaledOrthBuffer, 0); - - //============================================================== - // Start of source and target direction determination - - // Work through the preferred orientations by relative positioning - // of the vertices and list them in preferred and available order - - var dirPref = []; - var horPref = []; - var vertPref = []; - - horPref[0] = (sourceLeftDist >= sourceRightDist) ? mxConstants.DIRECTION_MASK_WEST - : mxConstants.DIRECTION_MASK_EAST; - vertPref[0] = (sourceTopDist >= sourceBottomDist) ? mxConstants.DIRECTION_MASK_NORTH - : mxConstants.DIRECTION_MASK_SOUTH; - - horPref[1] = mxUtils.reversePortConstraints(horPref[0]); - vertPref[1] = mxUtils.reversePortConstraints(vertPref[0]); - - var preferredHorizDist = sourceLeftDist >= sourceRightDist ? sourceLeftDist - : sourceRightDist; - var preferredVertDist = sourceTopDist >= sourceBottomDist ? sourceTopDist - : sourceBottomDist; - - var prefOrdering = [ [0, 0] , [0, 0] ]; - var preferredOrderSet = false; - - // If the preferred port isn't available, switch it - for (var i = 0; i < 2; i++) - { - if (dir[i] != 0x0) - { - continue; - } - - if ((horPref[i] & portConstraint[i]) == 0) - { - horPref[i] = mxUtils.reversePortConstraints(horPref[i]); - } - - if ((vertPref[i] & portConstraint[i]) == 0) - { - vertPref[i] = mxUtils - .reversePortConstraints(vertPref[i]); - } - - prefOrdering[i][0] = vertPref[i]; - prefOrdering[i][1] = horPref[i]; - } - - if (preferredVertDist > scaledOrthBuffer * 2 - && preferredHorizDist > scaledOrthBuffer * 2) - { - // Possibility of two segment edge connection - if (((horPref[0] & portConstraint[0]) > 0) - && ((vertPref[1] & portConstraint[1]) > 0)) - { - prefOrdering[0][0] = horPref[0]; - prefOrdering[0][1] = vertPref[0]; - prefOrdering[1][0] = vertPref[1]; - prefOrdering[1][1] = horPref[1]; - preferredOrderSet = true; - } - else if (((vertPref[0] & portConstraint[0]) > 0) - && ((horPref[1] & portConstraint[1]) > 0)) - { - prefOrdering[0][0] = vertPref[0]; - prefOrdering[0][1] = horPref[0]; - prefOrdering[1][0] = horPref[1]; - prefOrdering[1][1] = vertPref[1]; - preferredOrderSet = true; - } - } - if (preferredVertDist > scaledOrthBuffer * 2 && !preferredOrderSet) - { - prefOrdering[0][0] = vertPref[0]; - prefOrdering[0][1] = horPref[0]; - prefOrdering[1][0] = vertPref[1]; - prefOrdering[1][1] = horPref[1]; - preferredOrderSet = true; - - } - if (preferredHorizDist > scaledOrthBuffer * 2 && !preferredOrderSet) - { - prefOrdering[0][0] = horPref[0]; - prefOrdering[0][1] = vertPref[0]; - prefOrdering[1][0] = horPref[1]; - prefOrdering[1][1] = vertPref[1]; - preferredOrderSet = true; - } - - // The source and target prefs are now an ordered list of - // the preferred port selections - // It the list can contain gaps, compact it - - for (var i = 0; i < 2; i++) - { - if (dir[i] != 0x0) - { - continue; - } - - if ((prefOrdering[i][0] & portConstraint[i]) == 0) - { - prefOrdering[i][0] = prefOrdering[i][1]; - } - - dirPref[i] = prefOrdering[i][0] & portConstraint[i]; - dirPref[i] |= (prefOrdering[i][1] & portConstraint[i]) << 8; - dirPref[i] |= (prefOrdering[1 - i][i] & portConstraint[i]) << 16; - dirPref[i] |= (prefOrdering[1 - i][1 - i] & portConstraint[i]) << 24; - - if ((dirPref[i] & 0xF) == 0) - { - dirPref[i] = dirPref[i] << 8; - } - if ((dirPref[i] & 0xF00) == 0) - { - dirPref[i] = (dirPref[i] & 0xF) | dirPref[i] >> 8; - } - if ((dirPref[i] & 0xF0000) == 0) - { - dirPref[i] = (dirPref[i] & 0xFFFF) - | ((dirPref[i] & 0xF000000) >> 8); - } - - dir[i] = dirPref[i] & 0xF; - - if (portConstraint[i] == mxConstants.DIRECTION_MASK_WEST - || portConstraint[i] == mxConstants.DIRECTION_MASK_NORTH - || portConstraint[i] == mxConstants.DIRECTION_MASK_EAST - || portConstraint[i] == mxConstants.DIRECTION_MASK_SOUTH) - { - dir[i] = portConstraint[i]; - } - } - - //============================================================== - // End of source and target direction determination - - var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[0]; - var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[1]; - - sourceIndex -= quad; - targetIndex -= quad; - - if (sourceIndex < 1) - { - sourceIndex += 4; - } - if (targetIndex < 1) - { - targetIndex += 4; - } - - var routePattern = mxEdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1]; - - mxEdgeStyle.wayPoints1[0][0] = geo[0][0]; - mxEdgeStyle.wayPoints1[0][1] = geo[0][1]; - - switch (dir[0]) - { - case mxConstants.DIRECTION_MASK_WEST: - mxEdgeStyle.wayPoints1[0][0] -= scaledOrthBuffer; - mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3]; - break; - case mxConstants.DIRECTION_MASK_SOUTH: - mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2]; - mxEdgeStyle.wayPoints1[0][1] += geo[0][3] + scaledOrthBuffer; - break; - case mxConstants.DIRECTION_MASK_EAST: - mxEdgeStyle.wayPoints1[0][0] += geo[0][2] + scaledOrthBuffer; - mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3]; - break; - case mxConstants.DIRECTION_MASK_NORTH: - mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2]; - mxEdgeStyle.wayPoints1[0][1] -= scaledOrthBuffer; - break; - } - - var currentIndex = 0; - - // Orientation, 0 horizontal, 1 vertical - var lastOrientation = (dir[0] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0 - : 1; - var initialOrientation = lastOrientation; - var currentOrientation = 0; - - for (var i = 0; i < routePattern.length; i++) - { - var nextDirection = routePattern[i] & 0xF; - - // Rotate the index of this direction by the quad - // to get the real direction - var directionIndex = nextDirection == mxConstants.DIRECTION_MASK_EAST ? 3 - : nextDirection; - - directionIndex += quad; - - if (directionIndex > 4) - { - directionIndex -= 4; - } - - var direction = mxEdgeStyle.dirVectors[directionIndex - 1]; - - currentOrientation = (directionIndex % 2 > 0) ? 0 : 1; - // Only update the current index if the point moved - // in the direction of the current segment move, - // otherwise the same point is moved until there is - // a segment direction change - if (currentOrientation != lastOrientation) - { - currentIndex++; - // Copy the previous way point into the new one - // We can't base the new position on index - 1 - // because sometime elbows turn out not to exist, - // then we'd have to rewind. - mxEdgeStyle.wayPoints1[currentIndex][0] = mxEdgeStyle.wayPoints1[currentIndex - 1][0]; - mxEdgeStyle.wayPoints1[currentIndex][1] = mxEdgeStyle.wayPoints1[currentIndex - 1][1]; - } - - var tar = (routePattern[i] & mxEdgeStyle.TARGET_MASK) > 0; - var sou = (routePattern[i] & mxEdgeStyle.SOURCE_MASK) > 0; - var side = (routePattern[i] & mxEdgeStyle.SIDE_MASK) >> 5; - side = side << quad; - - if (side > 0xF) - { - side = side >> 4; - } - - var center = (routePattern[i] & mxEdgeStyle.CENTER_MASK) > 0; - - if ((sou || tar) && side < 9) - { - var limit = 0; - var souTar = sou ? 0 : 1; - - if (center && currentOrientation == 0) - { - limit = geo[souTar][0] + constraint[souTar][0] * geo[souTar][2]; - } - else if (center) - { - limit = geo[souTar][1] + constraint[souTar][1] * geo[souTar][3]; - } - else - { - limit = mxEdgeStyle.limits[souTar][side]; - } - - if (currentOrientation == 0) - { - var lastX = mxEdgeStyle.wayPoints1[currentIndex][0]; - var deltaX = (limit - lastX) * direction[0]; - - if (deltaX > 0) - { - mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0] - * deltaX; - } - } - else - { - var lastY = mxEdgeStyle.wayPoints1[currentIndex][1]; - var deltaY = (limit - lastY) * direction[1]; - - if (deltaY > 0) - { - mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1] - * deltaY; - } - } - } - - else if (center) - { - // Which center we're travelling to depend on the current direction - mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0] - * Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2); - mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1] - * Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2); - } - - if (currentIndex > 0 - && mxEdgeStyle.wayPoints1[currentIndex][currentOrientation] == mxEdgeStyle.wayPoints1[currentIndex - 1][currentOrientation]) - { - currentIndex--; - } - else - { - lastOrientation = currentOrientation; - } - } - - for (var i = 0; i <= currentIndex; i++) - { - if (i == currentIndex) - { - // Last point can cause last segment to be in - // same direction as jetty/approach. If so, - // check the number of points is consistent - // with the relative orientation of source and target - // jettys. Same orientation requires an even - // number of turns (points), different requires - // odd. - var targetOrientation = (dir[1] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0 - : 1; - var sameOrient = targetOrientation == initialOrientation ? 0 : 1; - - // (currentIndex + 1) % 2 is 0 for even number of points, - // 1 for odd - if (sameOrient != (currentIndex + 1) % 2) - { - // The last point isn't required - break; - } - } - - result.push(new mxPoint(mxEdgeStyle.wayPoints1[i][0], mxEdgeStyle.wayPoints1[i][1])); - } - }, - - getRoutePattern: function(dir, quad, dx, dy) - { - var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[0]; - var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[1]; - - sourceIndex -= quad; - targetIndex -= quad; - - if (sourceIndex < 1) - { - sourceIndex += 4; - } - if (targetIndex < 1) - { - targetIndex += 4; - } - - var result = routePatterns[sourceIndex - 1][targetIndex - 1]; - - if (dx == 0 || dy == 0) - { - if (inlineRoutePatterns[sourceIndex - 1][targetIndex - 1] != null) - { - result = inlineRoutePatterns[sourceIndex - 1][targetIndex - 1]; - } - } - - return result; - } -};
\ No newline at end of file diff --git a/src/js/view/mxGraph.js b/src/js/view/mxGraph.js deleted file mode 100644 index 7c90f9b..0000000 --- a/src/js/view/mxGraph.js +++ /dev/null @@ -1,11176 +0,0 @@ -/** - * $Id: mxGraph.js,v 1.702 2012-12-13 15:07:34 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraph - * - * Extends <mxEventSource> to implement a graph component for - * the browser. This is the main class of the package. To activate - * panning and connections use <setPanning> and <setConnectable>. - * For rubberband selection you must create a new instance of - * <mxRubberband>. The following listeners are added to - * <mouseListeners> by default: - * - * - <tooltipHandler>: <mxTooltipHandler> that displays tooltips - * - <panningHandler>: <mxPanningHandler> for panning and popup menus - * - <connectionHandler>: <mxConnectionHandler> for creating connections - * - <graphHandler>: <mxGraphHandler> for moving and cloning cells - * - * These listeners will be called in the above order if they are enabled. - * - * Background Images: - * - * To display a background image, set the image, image width and - * image height using <setBackgroundImage>. If one of the - * above values has changed then the <view>'s <mxGraphView.validate> - * should be invoked. - * - * Cell Images: - * - * To use images in cells, a shape must be specified in the default - * vertex style (or any named style). Possible shapes are - * <mxConstants.SHAPE_IMAGE> and <mxConstants.SHAPE_LABEL>. - * The code to change the shape used in the default vertex style, - * the following code is used: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE; - * (end) - * - * For the default vertex style, the image to be displayed can be - * specified in a cell's style using the <mxConstants.STYLE_IMAGE> - * key and the image URL as a value, for example: - * - * (code) - * image=http://www.example.com/image.gif - * (end) - * - * For a named style, the the stylename must be the first element - * of the cell style: - * - * (code) - * stylename;image=http://www.example.com/image.gif - * (end) - * - * A cell style can have any number of key=value pairs added, divided - * by a semicolon as follows: - * - * (code) - * [stylename;|key=value;] - * (end) - * - * Labels: - * - * The cell labels are defined by <getLabel> which uses <convertValueToString> - * if <labelsVisible> is true. If a label must be rendered as HTML markup, then - * <isHtmlLabel> should return true for the respective cell. If all labels - * contain HTML markup, <htmlLabels> can be set to true. NOTE: Enabling HTML - * labels carries a possible security risk (see the section on security in - * the manual). - * - * If wrapping is needed for a label, then <isHtmlLabel> and <isWrapping> must - * return true for the cell whose label should be wrapped. See <isWrapping> for - * an example. - * - * If clipping is needed to keep the rendering of a HTML label inside the - * bounds of its vertex, then <isClipping> should return true for the - * respective cell. - * - * By default, edge labels are movable and vertex labels are fixed. This can be - * changed by setting <edgeLabelsMovable> and <vertexLabelsMovable>, or by - * overriding <isLabelMovable>. - * - * In-place Editing: - * - * In-place editing is started with a doubleclick or by typing F2. - * Programmatically, <edit> is used to check if the cell is editable - * (<isCellEditable>) and call <startEditingAtCell>, which invokes - * <mxCellEditor.startEditing>. The editor uses the value returned - * by <getEditingValue> as the editing value. - * - * After in-place editing, <labelChanged> is called, which invokes - * <mxGraphModel.setValue>, which in turn calls - * <mxGraphModel.valueForCellChanged> via <mxValueChange>. - * - * The event that triggers in-place editing is passed through to the - * <cellEditor>, which may take special actions depending on the type of the - * event or mouse location, and is also passed to <getEditingValue>. The event - * is then passed back to the event processing functions which can perform - * specific actions based on the trigger event. - * - * Tooltips: - * - * Tooltips are implemented by <getTooltip>, which calls <getTooltipForCell> - * if a cell is under the mousepointer. The default implementation checks if - * the cell has a getTooltip function and calls it if it exists. Hence, in order - * to provide custom tooltips, the cell must provide a getTooltip function, or - * one of the two above functions must be overridden. - * - * Typically, for custom cell tooltips, the latter function is overridden as - * follows: - * - * (code) - * graph.getTooltipForCell = function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * (end) - * - * When using a config file, the function is overridden in the mxGraph section - * using the following entry: - * - * (code) - * <add as="getTooltipForCell"><![CDATA[ - * function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * ]]></add> - * (end) - * - * "this" refers to the graph in the implementation, so for example to check if - * a cell is an edge, you use this.getModel().isEdge(cell) - * - * For replacing the default implementation of <getTooltipForCell> (rather than - * replacing the function on a specific instance), the following code should be - * used after loading the JavaScript files, but before creating a new mxGraph - * instance using <mxGraph>: - * - * (code) - * mxGraph.prototype.getTooltipForCell = function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * (end) - * - * Shapes & Styles: - * - * The implementation of new shapes is demonstrated in the examples. We'll assume - * that we have implemented a custom shape with the name BoxShape which we want - * to use for drawing vertices. To use this shape, it must first be registered in - * the cell renderer as follows: - * - * (code) - * graph.cellRenderer.registerShape('box', BoxShape); - * (end) - * - * The code registers the BoxShape constructor under the name box in the cell - * renderer of the graph. The shape can now be referenced using the shape-key in - * a style definition. (The cell renderer contains a set of additional shapes, - * namely one for each constant with a SHAPE-prefix in <mxConstants>.) - * - * Styles are a collection of key, value pairs and a stylesheet is a collection - * of named styles. The names are referenced by the cellstyle, which is stored - * in <mxCell.style> with the following format: [stylename;|key=value;]. The - * string is resolved to a collection of key, value pairs, where the keys are - * overridden with the values in the string. - * - * When introducing a new shape, the name under which the shape is registered - * must be used in the stylesheet. There are three ways of doing this: - * - * - By changing the default style, so that all vertices will use the new - * shape - * - By defining a new style, so that only vertices with the respective - * cellstyle will use the new shape - * - By using shape=box in the cellstyle's optional list of key, value pairs - * to be overridden - * - * In the first case, the code to fetch and modify the default style for - * vertices is as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_SHAPE] = 'box'; - * (end) - * - * The code takes the default vertex style, which is used for all vertices that - * do not have a specific cellstyle, and modifies the value for the shape-key - * in-place to use the new BoxShape for drawing vertices. This is done by - * assigning the box value in the second line, which refers to the name of the - * BoxShape in the cell renderer. - * - * In the second case, a collection of key, value pairs is created and then - * added to the stylesheet under a new name. In order to distinguish the - * shapename and the stylename we'll use boxstyle for the stylename: - * - * (code) - * var style = new Object(); - * style[mxConstants.STYLE_SHAPE] = 'box'; - * style[mxConstants.STYLE_STROKECOLOR] = '#000000'; - * style[mxConstants.STYLE_FONTCOLOR] = '#000000'; - * graph.getStylesheet().putCellStyle('boxstyle', style); - * (end) - * - * The code adds a new style with the name boxstyle to the stylesheet. To use - * this style with a cell, it must be referenced from the cellstyle as follows: - * - * (code) - * var vertex = graph.insertVertex(parent, null, 'Hello, World!', 20, 20, 80, 20, - * 'boxstyle'); - * (end) - * - * To summarize, each new shape must be registered in the <mxCellRenderer> with - * a unique name. That name is then used as the value of the shape-key in a - * default or custom style. If there are multiple custom shapes, then there - * should be a separate style for each shape. - * - * Inheriting Styles: - * - * For fill-, stroke-, gradient- and indicatorColors special keywords can be - * used. The inherit keyword for one of these colors will inherit the color - * for the same key from the parent cell. The swimlane keyword does the same, - * but inherits from the nearest swimlane in the ancestor hierarchy. Finally, - * the indicated keyword will use the color of the indicator as the color for - * the given key. - * - * Scrollbars: - * - * The <containers> overflow CSS property defines if scrollbars are used to - * display the graph. For values of 'auto' or 'scroll', the scrollbars will - * be shown. Note that the <resizeContainer> flag is normally not used - * together with scrollbars, as it will resize the container to match the - * size of the graph after each change. - * - * Multiplicities and Validation: - * - * To control the possible connections in mxGraph, <getEdgeValidationError> is - * used. The default implementation of the function uses <multiplicities>, - * which is an array of <mxMultiplicity>. Using this class allows to establish - * simple multiplicities, which are enforced by the graph. - * - * The <mxMultiplicity> uses <mxCell.is> to determine for which terminals it - * applies. The default implementation of <mxCell.is> works with DOM nodes (XML - * nodes) and checks if the given type parameter matches the nodeName of the - * node (case insensitive). Optionally, an attributename and value can be - * specified which are also checked. - * - * <getEdgeValidationError> is called whenever the connectivity of an edge - * changes. It returns an empty string or an error message if the edge is - * invalid or null if the edge is valid. If the returned string is not empty - * then it is displayed as an error message. - * - * <mxMultiplicity> allows to specify the multiplicity between a terminal and - * its possible neighbors. For example, if any rectangle may only be connected - * to, say, a maximum of two circles you can add the following rule to - * <multiplicities>: - * - * (code) - * graph.multiplicities.push(new mxMultiplicity( - * true, 'rectangle', null, null, 0, 2, ['circle'], - * 'Only 2 targets allowed', - * 'Only shape targets allowed')); - * (end) - * - * This will display the first error message whenever a rectangle is connected - * to more than two circles and the second error message if a rectangle is - * connected to anything but a circle. - * - * For certain multiplicities, such as a minimum of 1 connection, which cannot - * be enforced at cell creation time (unless the cell is created together with - * the connection), mxGraph offers <validate> which checks all multiplicities - * for all cells and displays the respective error messages in an overlay icon - * on the cells. - * - * If a cell is collapsed and contains validation errors, a respective warning - * icon is attached to the collapsed cell. - * - * Auto-Layout: - * - * For automatic layout, the <getLayout> hook is provided in <mxLayoutManager>. - * It can be overridden to return a layout algorithm for the children of a - * given cell. - * - * Unconnected edges: - * - * The default values for all switches are designed to meet the requirements of - * general diagram drawing applications. A very typical set of settings to - * avoid edges that are not connected is the following: - * - * (code) - * graph.setAllowDanglingEdges(false); - * graph.setDisconnectOnMove(false); - * (end) - * - * Setting the <cloneInvalidEdges> switch to true is optional. This switch - * controls if edges are inserted after a copy, paste or clone-drag if they are - * invalid. For example, edges are invalid if copied or control-dragged without - * having selected the corresponding terminals and allowDanglingEdges is - * false, in which case the edges will not be cloned if the switch is false. - * - * Output: - * - * To produce an XML representation for a diagram, the following code can be - * used. - * - * (code) - * var enc = new mxCodec(mxUtils.createXmlDocument()); - * var node = enc.encode(graph.getModel()); - * (end) - * - * This will produce an XML node than can be handled using the DOM API or - * turned into a string representation using the following code: - * - * (code) - * var xml = mxUtils.getXml(node); - * (end) - * - * To obtain a formatted string, mxUtils.getPrettyXml can be used instead. - * - * This string can now be stored in a local persistent storage (for example - * using Google Gears) or it can be passed to a backend using mxUtils.post as - * follows. The url variable is the URL of the Java servlet, PHP page or HTTP - * handler, depending on the server. - * - * (code) - * var xmlString = encodeURIComponent(mxUtils.getXml(node)); - * mxUtils.post(url, 'xml='+xmlString, function(req) - * { - * // Process server response using req of type mxXmlRequest - * }); - * (end) - * - * Input: - * - * To load an XML representation of a diagram into an existing graph object - * mxUtils.load can be used as follows. The url variable is the URL of the Java - * servlet, PHP page or HTTP handler that produces the XML string. - * - * (code) - * var xmlDoc = mxUtils.load(url).getXml(); - * var node = xmlDoc.documentElement; - * var dec = new mxCodec(node.ownerDocument); - * dec.decode(node, graph.getModel()); - * (end) - * - * For creating a page that loads the client and a diagram using a single - * request please refer to the deployment examples in the backends. - * - * Functional dependencies: - * - * (see images/callgraph.png) - * - * Resources: - * - * resources/graph - Language resources for mxGraph - * - * Group: Events - * - * Event: mxEvent.ROOT - * - * Fires if the root in the model has changed. This event has no properties. - * - * Event: mxEvent.ALIGN_CELLS - * - * Fires between begin- and endUpdate in <alignCells>. The <code>cells</code> - * and <code>align</code> properties contain the respective arguments that were - * passed to <alignCells>. - * - * Event: mxEvent.FLIP_EDGE - * - * Fires between begin- and endUpdate in <flipEdge>. The <code>edge</code> - * property contains the edge passed to <flipEdge>. - * - * Event: mxEvent.ORDER_CELLS - * - * Fires between begin- and endUpdate in <orderCells>. The <code>cells</code> - * and <code>back</code> properties contain the respective arguments that were - * passed to <orderCells>. - * - * Event: mxEvent.CELLS_ORDERED - * - * Fires between begin- and endUpdate in <cellsOrdered>. The <code>cells</code> - * and <code>back</code> arguments contain the respective arguments that were - * passed to <cellsOrdered>. - * - * Event: mxEvent.GROUP_CELLS - * - * Fires between begin- and endUpdate in <groupCells>. The <code>group</code>, - * <code>cells</code> and <code>border</code> arguments contain the respective - * arguments that were passed to <groupCells>. - * - * Event: mxEvent.UNGROUP_CELLS - * - * Fires between begin- and endUpdate in <ungroupCells>. The <code>cells</code> - * property contains the array of cells that was passed to <ungroupCells>. - * - * Event: mxEvent.REMOVE_CELLS_FROM_PARENT - * - * Fires between begin- and endUpdate in <removeCellsFromParent>. The - * <code>cells</code> property contains the array of cells that was passed to - * <removeCellsFromParent>. - * - * Event: mxEvent.ADD_CELLS - * - * Fires between begin- and endUpdate in <addCells>. The <code>cells</code>, - * <code>parent</code>, <code>index</code>, <code>source</code> and - * <code>target</code> properties contain the respective arguments that were - * passed to <addCells>. - * - * Event: mxEvent.CELLS_ADDED - * - * Fires between begin- and endUpdate in <cellsAdded>. The <code>cells</code>, - * <code>parent</code>, <code>index</code>, <code>source</code>, - * <code>target</code> and <code>absolute</code> properties contain the - * respective arguments that were passed to <cellsAdded>. - * - * Event: mxEvent.REMOVE_CELLS - * - * Fires between begin- and endUpdate in <removeCells>. The <code>cells</code> - * and <code>includeEdges</code> arguments contain the respective arguments - * that were passed to <removeCells>. - * - * Event: mxEvent.CELLS_REMOVED - * - * Fires between begin- and endUpdate in <cellsRemoved>. The <code>cells</code> - * argument contains the array of cells that was removed. - * - * Event: mxEvent.SPLIT_EDGE - * - * Fires between begin- and endUpdate in <splitEdge>. The <code>edge</code> - * property contains the edge to be splitted, the <code>cells</code>, - * <code>newEdge</code>, <code>dx</code> and <code>dy</code> properties contain - * the respective arguments that were passed to <splitEdge>. - * - * Event: mxEvent.TOGGLE_CELLS - * - * Fires between begin- and endUpdate in <toggleCells>. The <code>show</code>, - * <code>cells</code> and <code>includeEdges</code> properties contain the - * respective arguments that were passed to <toggleCells>. - * - * Event: mxEvent.FOLD_CELLS - * - * Fires between begin- and endUpdate in <foldCells>. The - * <code>collapse</code>, <code>cells</code> and <code>recurse</code> - * properties contain the respective arguments that were passed to <foldCells>. - * - * Event: mxEvent.CELLS_FOLDED - * - * Fires between begin- and endUpdate in cellsFolded. The - * <code>collapse</code>, <code>cells</code> and <code>recurse</code> - * properties contain the respective arguments that were passed to - * <cellsFolded>. - * - * Event: mxEvent.UPDATE_CELL_SIZE - * - * Fires between begin- and endUpdate in <updateCellSize>. The - * <code>cell</code> and <code>ignoreChildren</code> properties contain the - * respective arguments that were passed to <updateCellSize>. - * - * Event: mxEvent.RESIZE_CELLS - * - * Fires between begin- and endUpdate in <resizeCells>. The <code>cells</code> - * and <code>bounds</code> properties contain the respective arguments that - * were passed to <resizeCells>. - * - * Event: mxEvent.CELLS_RESIZED - * - * Fires between begin- and endUpdate in <cellsResized>. The <code>cells</code> - * and <code>bounds</code> properties contain the respective arguments that - * were passed to <cellsResized>. - * - * Event: mxEvent.MOVE_CELLS - * - * Fires between begin- and endUpdate in <moveCells>. The <code>cells</code>, - * <code>dx</code>, <code>dy</code>, <code>clone</code>, <code>target</code> - * and <code>event</code> properties contain the respective arguments that - * were passed to <moveCells>. - * - * Event: mxEvent.CELLS_MOVED - * - * Fires between begin- and endUpdate in <cellsMoved>. The <code>cells</code>, - * <code>dx</code>, <code>dy</code> and <code>disconnect</code> properties - * contain the respective arguments that were passed to <cellsMoved>. - * - * Event: mxEvent.CONNECT_CELL - * - * Fires between begin- and endUpdate in <connectCell>. The <code>edge</code>, - * <code>terminal</code> and <code>source</code> properties contain the - * respective arguments that were passed to <connectCell>. - * - * Event: mxEvent.CELL_CONNECTED - * - * Fires between begin- and endUpdate in <cellConnected>. The - * <code>edge</code>, <code>terminal</code> and <code>source</code> properties - * contain the respective arguments that were passed to <cellConnected>. - * - * Event: mxEvent.REFRESH - * - * Fires after <refresh> was executed. This event has no properties. - * - * Event: mxEvent.CLICK - * - * Fires in <click> after a click event. The <code>event</code> property - * contains the original mouse event and <code>cell</code> property contains - * the cell under the mouse or null if the background was clicked. - * - * To handle a click event, use the following code: - * - * (code) - * graph.addListener(mxEvent.CLICK, function(sender, evt) - * { - * var e = evt.getProperty('event'); // mouse event - * var cell = evt.getProperty('cell'); // cell may be null - * - * if (!evt.isConsumed()) - * { - * if (cell != null) - * { - * // Do something useful with cell and consume the event - * evt.consume(); - * } - * } - * }); - * (end) - * - * Event: mxEvent.DOUBLE_CLICK - * - * Fires in <dblClick> after a double click. The <code>event</code> property - * contains the original mouse event and the <code>cell</code> property - * contains the cell under the mouse or null if the background was clicked. - * - * Event: mxEvent.SIZE - * - * Fires after <sizeDidChange> was executed. The <code>bounds</code> property - * contains the new graph bounds. - * - * Event: mxEvent.START_EDITING - * - * Fires before the in-place editor starts in <startEditingAtCell>. The - * <code>cell</code> property contains the cell that is being edited and the - * <code>event</code> property contains the optional event argument that was - * passed to <startEditingAtCell>. - * - * Event: mxEvent.LABEL_CHANGED - * - * Fires between begin- and endUpdate in <cellLabelChanged>. The - * <code>cell</code> property contains the cell, the <code>value</code> - * property contains the new value for the cell and the optional - * <code>event</code> property contains the mouse event that started the edit. - * - * Event: mxEvent.ADD_OVERLAY - * - * Fires after an overlay is added in <addCellOverlay>. The <code>cell</code> - * property contains the cell and the <code>overlay</code> property contains - * the <mxCellOverlay> that was added. - * - * Event: mxEvent.REMOVE_OVERLAY - * - * Fires after an overlay is removed in <removeCellOverlay> and - * <removeCellOverlays>. The <code>cell</code> property contains the cell and - * the <code>overlay</code> property contains the <mxCellOverlay> that was - * removed. - * - * Constructor: mxGraph - * - * Constructs a new mxGraph in the specified container. Model is an optional - * mxGraphModel. If no model is provided, a new mxGraphModel instance is - * used as the model. The container must have a valid owner document prior - * to calling this function in Internet Explorer. RenderHint is a string to - * affect the display performance and rendering in IE, but not in SVG-based - * browsers. The parameter is mapped to <dialect>, which may - * be one of <mxConstants.DIALECT_SVG> for SVG-based browsers, - * <mxConstants.DIALECT_STRICTHTML> for fastest display mode, - * <mxConstants.DIALECT_PREFERHTML> for faster display mode, - * <mxConstants.DIALECT_MIXEDHTML> for fast and <mxConstants.DIALECT_VML> - * for exact display mode (slowest). The dialects are defined in mxConstants. - * The default values are DIALECT_SVG for SVG-based browsers and - * DIALECT_MIXED for IE. - * - * The possible values for the renderingHint parameter are explained below: - * - * fast - The parameter is based on the fact that the display performance is - * highly improved in IE if the VML is not contained within a VML group - * element. The lack of a group element only slightly affects the display while - * panning, but improves the performance by almost a factor of 2, while keeping - * the display sufficiently accurate. This also allows to render certain shapes as HTML - * if the display accuracy is not affected, which is implemented by - * <mxShape.isMixedModeHtml>. This is the default setting and is mapped to - * DIALECT_MIXEDHTML. - * faster - Same as fast, but more expensive shapes are avoided. This is - * controlled by <mxShape.preferModeHtml>. The default implementation will - * avoid gradients and rounded rectangles, but more significant shapes, such - * as rhombus, ellipse, actor and cylinder will be rendered accurately. This - * setting is mapped to DIALECT_PREFERHTML. - * fastest - Almost anything will be rendered in Html. This allows for - * rectangles, labels and images. This setting is mapped to - * DIALECT_STRICTHTML. - * exact - If accurate panning is required and if the diagram is small (up - * to 100 cells), then this value should be used. In this mode, a group is - * created that contains the VML. This allows for accurate panning and is - * mapped to DIALECT_VML. - * - * Example: - * - * To create a graph inside a DOM node with an id of graph: - * (code) - * var container = document.getElementById('graph'); - * var graph = new mxGraph(container); - * (end) - * - * Parameters: - * - * container - Optional DOM node that acts as a container for the graph. - * If this is null then the container can be initialized later using - * <init>. - * model - Optional <mxGraphModel> that constitutes the graph data. - * renderHint - Optional string that specifies the display accuracy and - * performance. Default is mxConstants.DIALECT_MIXEDHTML (for IE). - * stylesheet - Optional <mxStylesheet> to be used in the graph. - */ -function mxGraph(container, model, renderHint, stylesheet) -{ - // Initializes the variable in case the prototype has been - // modified to hold some listeners (which is possible because - // the createHandlers call is executed regardless of the - // arguments passed into the ctor). - this.mouseListeners = null; - - // Converts the renderHint into a dialect - this.renderHint = renderHint; - - if (mxClient.IS_SVG) - { - this.dialect = mxConstants.DIALECT_SVG; - } - else if (renderHint == mxConstants.RENDERING_HINT_EXACT && mxClient.IS_VML) - { - this.dialect = mxConstants.DIALECT_VML; - } - else if (renderHint == mxConstants.RENDERING_HINT_FASTEST) - { - this.dialect = mxConstants.DIALECT_STRICTHTML; - } - else if (renderHint == mxConstants.RENDERING_HINT_FASTER) - { - this.dialect = mxConstants.DIALECT_PREFERHTML; - } - else // default for VML - { - this.dialect = mxConstants.DIALECT_MIXEDHTML; - } - - // Initializes the main members that do not require a container - this.model = (model != null) ? model : new mxGraphModel(); - this.multiplicities = []; - this.imageBundles = []; - this.cellRenderer = this.createCellRenderer(); - this.setSelectionModel(this.createSelectionModel()); - this.setStylesheet((stylesheet != null) ? stylesheet : this.createStylesheet()); - this.view = this.createGraphView(); - - // Adds a graph model listener to update the view - this.graphModelChangeListener = mxUtils.bind(this, function(sender, evt) - { - this.graphModelChanged(evt.getProperty('edit').changes); - }); - - this.model.addListener(mxEvent.CHANGE, this.graphModelChangeListener); - - // Installs basic event handlers with disabled default settings. - this.createHandlers(); - - // Initializes the display if a container was specified - if (container != null) - { - this.init(container); - } - - this.view.revalidate(); -}; - -/** - * Installs the required language resources at class - * loading time. - */ -if (mxLoadResources) -{ - mxResources.add(mxClient.basePath+'/resources/graph'); -} - -/** - * Extends mxEventSource. - */ -mxGraph.prototype = new mxEventSource(); -mxGraph.prototype.constructor = mxGraph; - -/** - * Variable: EMPTY_ARRAY - * - * Immutable empty array instance. - */ -mxGraph.prototype.EMPTY_ARRAY = []; - -/** - * Group: Variables - */ - -/** - * Variable: mouseListeners - * - * Holds the mouse event listeners. See <fireMouseEvent>. - */ -mxGraph.prototype.mouseListeners = null; - -/** - * Variable: isMouseDown - * - * Holds the state of the mouse button. - */ -mxGraph.prototype.isMouseDown = false; - -/** - * Variable: model - * - * Holds the <mxGraphModel> that contains the cells to be displayed. - */ -mxGraph.prototype.model = null; - -/** - * Variable: view - * - * Holds the <mxGraphView> that caches the <mxCellStates> for the cells. - */ -mxGraph.prototype.view = null; - -/** - * Variable: stylesheet - * - * Holds the <mxStylesheet> that defines the appearance of the cells. - * - * - * Example: - * - * Use the following code to read a stylesheet into an existing graph. - * - * (code) - * var req = mxUtils.load('stylesheet.xml'); - * var root = req.getDocumentElement(); - * var dec = new mxCodec(root.ownerDocument); - * dec.decode(root, graph.stylesheet); - * (end) - */ -mxGraph.prototype.stylesheet = null; - -/** - * Variable: selectionModel - * - * Holds the <mxGraphSelectionModel> that models the current selection. - */ -mxGraph.prototype.selectionModel = null; - -/** - * Variable: cellEditor - * - * Holds the <mxCellEditor> that is used as the in-place editing. - */ -mxGraph.prototype.cellEditor = null; - -/** - * Variable: cellRenderer - * - * Holds the <mxCellRenderer> for rendering the cells in the graph. - */ -mxGraph.prototype.cellRenderer = null; - -/** - * Variable: multiplicities - * - * An array of <mxMultiplicities> describing the allowed - * connections in a graph. - */ -mxGraph.prototype.multiplicities = null; - -/** - * Variable: renderHint - * - * RenderHint as it was passed to the constructor. - */ -mxGraph.prototype.renderHint = null; - -/** - * Variable: dialect - * - * Dialect to be used for drawing the graph. Possible values are all - * constants in <mxConstants> with a DIALECT-prefix. - */ -mxGraph.prototype.dialect = null; - -/** - * Variable: gridSize - * - * Specifies the grid size. Default is 10. - */ -mxGraph.prototype.gridSize = 10; - -/** - * Variable: gridEnabled - * - * Specifies if the grid is enabled. This is used in <snap>. Default is - * true. - */ -mxGraph.prototype.gridEnabled = true; - -/** - * Variable: portsEnabled - * - * Specifies if ports are enabled. This is used in <cellConnected> to update - * the respective style. Default is true. - */ -mxGraph.prototype.portsEnabled = true; - -/** - * Variable: doubleTapEnabled - * - * Specifies if double taps on touch-based devices should be handled. Default - * is true. - */ -mxGraph.prototype.doubleTapEnabled = true; - -/** - * Variable: doubleTapTimeout - * - * Specifies the timeout for double taps. Default is 700 ms. - */ -mxGraph.prototype.doubleTapTimeout = 700; - -/** - * Variable: doubleTapTolerance - * - * Specifies the tolerance for double taps. Default is 25 pixels. - */ -mxGraph.prototype.doubleTapTolerance = 25; - -/** - * Variable: lastTouchX - * - * Holds the x-coordinate of the last touch event for double tap detection. - */ -mxGraph.prototype.lastTouchY = 0; - -/** - * Variable: lastTouchX - * - * Holds the y-coordinate of the last touch event for double tap detection. - */ -mxGraph.prototype.lastTouchY = 0; - -/** - * Variable: lastTouchTime - * - * Holds the time of the last touch event for double click detection. - */ -mxGraph.prototype.lastTouchTime = 0; - -/** - * Variable: gestureEnabled - * - * Specifies if the handleGesture method should be invoked. Default is true. This - * is an experimental feature for touch-based devices. - */ -mxGraph.prototype.gestureEnabled = true; - -/** - * Variable: tolerance - * - * Tolerance for a move to be handled as a single click. - * Default is 4 pixels. - */ -mxGraph.prototype.tolerance = 4; - -/** - * Variable: defaultOverlap - * - * Value returned by <getOverlap> if <isAllowOverlapParent> returns - * true for the given cell. <getOverlap> is used in <constrainChild> if - * <isConstrainChild> returns true. The value specifies the - * portion of the child which is allowed to overlap the parent. - */ -mxGraph.prototype.defaultOverlap = 0.5; - -/** - * Variable: defaultParent - * - * Specifies the default parent to be used to insert new cells. - * This is used in <getDefaultParent>. Default is null. - */ -mxGraph.prototype.defaultParent = null; - -/** - * Variable: alternateEdgeStyle - * - * Specifies the alternate edge style to be used if the main control point - * on an edge is being doubleclicked. Default is null. - */ -mxGraph.prototype.alternateEdgeStyle = null; - -/** - * Variable: backgroundImage - * - * Specifies the <mxImage> to be returned by <getBackgroundImage>. Default - * is null. - * - * Example: - * - * (code) - * var img = new mxImage('http://www.example.com/maps/examplemap.jpg', 1024, 768); - * graph.setBackgroundImage(img); - * graph.view.validate(); - * (end) - */ -mxGraph.prototype.backgroundImage = null; - -/** - * Variable: pageVisible - * - * Specifies if the background page should be visible. Default is false. - * Not yet implemented. - */ -mxGraph.prototype.pageVisible = false; - -/** - * Variable: pageBreaksVisible - * - * Specifies if a dashed line should be drawn between multiple pages. Default - * is false. If you change this value while a graph is being displayed then you - * should call <sizeDidChange> to force an update of the display. - */ -mxGraph.prototype.pageBreaksVisible = false; - -/** - * Variable: pageBreakColor - * - * Specifies the color for page breaks. Default is 'gray'. - */ -mxGraph.prototype.pageBreakColor = 'gray'; - -/** - * Variable: pageBreakDashed - * - * Specifies the page breaks should be dashed. Default is true. - */ -mxGraph.prototype.pageBreakDashed = true; - -/** - * Variable: minPageBreakDist - * - * Specifies the minimum distance for page breaks to be visible. Default is - * 20 (in pixels). - */ -mxGraph.prototype.minPageBreakDist = 20; - -/** - * Variable: preferPageSize - * - * Specifies if the graph size should be rounded to the next page number in - * <sizeDidChange>. This is only used if the graph container has scrollbars. - * Default is false. - */ -mxGraph.prototype.preferPageSize = false; - -/** - * Variable: pageFormat - * - * Specifies the page format for the background page. Default is - * <mxConstants.PAGE_FORMAT_A4_PORTRAIT>. This is used as the default in - * <mxPrintPreview> and for painting the background page if <pageVisible> is - * true and the pagebreaks if <pageBreaksVisible> is true. - */ -mxGraph.prototype.pageFormat = mxConstants.PAGE_FORMAT_A4_PORTRAIT; - -/** - * Variable: pageScale - * - * Specifies the scale of the background page. Default is 1.5. - * Not yet implemented. - */ -mxGraph.prototype.pageScale = 1.5; - -/** - * Variable: enabled - * - * Specifies the return value for <isEnabled>. Default is true. - */ -mxGraph.prototype.enabled = true; - -/** - * Variable: escapeEnabled - * - * Specifies if <mxKeyHandler> should invoke <escape> when the escape key - * is pressed. Default is true. - */ -mxGraph.prototype.escapeEnabled = true; - -/** - * Variable: invokesStopCellEditing - * - * If true, when editing is to be stopped by way of selection changing, - * data in diagram changing or other means stopCellEditing is invoked, and - * changes are saved. This is implemented in a focus handler in - * <mxCellEditor>. Default is true. - */ -mxGraph.prototype.invokesStopCellEditing = true; - -/** - * Variable: enterStopsCellEditing - * - * If true, pressing the enter key without pressing control or shift will stop - * editing and accept the new value. This is used in <mxCellEditor> to stop - * cell editing. Note: You can always use F2 and escape to stop editing. - * Default is false. - */ -mxGraph.prototype.enterStopsCellEditing = false; - -/** - * Variable: useScrollbarsForPanning - * - * Specifies if scrollbars should be used for panning in <panGraph> if - * any scrollbars are available. If scrollbars are enabled in CSS, but no - * scrollbars appear because the graph is smaller than the container size, - * then no panning occurs if this is true. Default is true. - */ -mxGraph.prototype.useScrollbarsForPanning = true; - -/** - * Variable: exportEnabled - * - * Specifies the return value for <canExportCell>. Default is true. - */ -mxGraph.prototype.exportEnabled = true; - -/** - * Variable: importEnabled - * - * Specifies the return value for <canImportCell>. Default is true. - */ -mxGraph.prototype.importEnabled = true; - -/** - * Variable: cellsLocked - * - * Specifies the return value for <isCellLocked>. Default is false. - */ -mxGraph.prototype.cellsLocked = false; - -/** - * Variable: cellsCloneable - * - * Specifies the return value for <isCellCloneable>. Default is true. - */ -mxGraph.prototype.cellsCloneable = true; - -/** - * Variable: foldingEnabled - * - * Specifies if folding (collapse and expand via an image icon in the graph - * should be enabled). Default is true. - */ -mxGraph.prototype.foldingEnabled = true; - -/** - * Variable: cellsEditable - * - * Specifies the return value for <isCellEditable>. Default is true. - */ -mxGraph.prototype.cellsEditable = true; - -/** - * Variable: cellsDeletable - * - * Specifies the return value for <isCellDeletable>. Default is true. - */ -mxGraph.prototype.cellsDeletable = true; - -/** - * Variable: cellsMovable - * - * Specifies the return value for <isCellMovable>. Default is true. - */ -mxGraph.prototype.cellsMovable = true; - -/** - * Variable: edgeLabelsMovable - * - * Specifies the return value for edges in <isLabelMovable>. Default is true. - */ -mxGraph.prototype.edgeLabelsMovable = true; - -/** - * Variable: vertexLabelsMovable - * - * Specifies the return value for vertices in <isLabelMovable>. Default is false. - */ -mxGraph.prototype.vertexLabelsMovable = false; - -/** - * Variable: dropEnabled - * - * Specifies the return value for <isDropEnabled>. Default is false. - */ -mxGraph.prototype.dropEnabled = false; - -/** - * Variable: splitEnabled - * - * Specifies if dropping onto edges should be enabled. Default is true. - */ -mxGraph.prototype.splitEnabled = true; - -/** - * Variable: cellsResizable - * - * Specifies the return value for <isCellResizable>. Default is true. - */ -mxGraph.prototype.cellsResizable = true; - -/** - * Variable: cellsBendable - * - * Specifies the return value for <isCellsBendable>. Default is true. - */ -mxGraph.prototype.cellsBendable = true; - -/** - * Variable: cellsSelectable - * - * Specifies the return value for <isCellSelectable>. Default is true. - */ -mxGraph.prototype.cellsSelectable = true; - -/** - * Variable: cellsDisconnectable - * - * Specifies the return value for <isCellDisconntable>. Default is true. - */ -mxGraph.prototype.cellsDisconnectable = true; - -/** - * Variable: autoSizeCells - * - * Specifies if the graph should automatically update the cell size after an - * edit. This is used in <isAutoSizeCell>. Default is false. - */ -mxGraph.prototype.autoSizeCells = false; - -/** - * Variable: autoScroll - * - * Specifies if the graph should automatically scroll if the mouse goes near - * the container edge while dragging. This is only taken into account if the - * container has scrollbars. Default is true. - * - * If you need this to work without scrollbars then set <ignoreScrollbars> to - * true. - */ -mxGraph.prototype.autoScroll = true; - -/** - * Variable: timerAutoScroll - * - * Specifies if timer-based autoscrolling should be used via mxPanningManager. - * Note that this disables the code in <scrollPointToVisible> and uses code in - * mxPanningManager instead. Note that <autoExtend> is disabled if this is - * true and that this should only be used with a scroll buffer or when - * scollbars are visible and scrollable in all directions. Default is false. - */ -mxGraph.prototype.timerAutoScroll = false; - -/** - * Variable: allowAutoPanning - * - * Specifies if panning via <panGraph> should be allowed to implement autoscroll - * if no scrollbars are available in <scrollPointToVisible>. Default is false. - */ -mxGraph.prototype.allowAutoPanning = false; - -/** - * Variable: ignoreScrollbars - * - * Specifies if the graph should automatically scroll regardless of the - * scrollbars. - */ -mxGraph.prototype.ignoreScrollbars = false; - -/** - * Variable: autoExtend - * - * Specifies if the size of the graph should be automatically extended if the - * mouse goes near the container edge while dragging. This is only taken into - * account if the container has scrollbars. Default is true. See <autoScroll>. - */ -mxGraph.prototype.autoExtend = true; - -/** - * Variable: maximumGraphBounds - * - * <mxRectangle> that specifies the area in which all cells in the diagram - * should be placed. Uses in <getMaximumGraphBounds>. Use a width or height of - * 0 if you only want to give a upper, left corner. - */ -mxGraph.prototype.maximumGraphBounds = null; - -/** - * Variable: minimumGraphSize - * - * <mxRectangle> that specifies the minimum size of the graph. This is ignored - * if the graph container has no scrollbars. Default is null. - */ -mxGraph.prototype.minimumGraphSize = null; - -/** - * Variable: minimumContainerSize - * - * <mxRectangle> that specifies the minimum size of the <container> if - * <resizeContainer> is true. - */ -mxGraph.prototype.minimumContainerSize = null; - -/** - * Variable: maximumContainerSize - * - * <mxRectangle> that specifies the maximum size of the container if - * <resizeContainer> is true. - */ -mxGraph.prototype.maximumContainerSize = null; - -/** - * Variable: resizeContainer - * - * Specifies if the container should be resized to the graph size when - * the graph size has changed. Default is false. - */ -mxGraph.prototype.resizeContainer = false; - -/** - * Variable: border - * - * Border to be added to the bottom and right side when the container is - * being resized after the graph has been changed. Default is 0. - */ -mxGraph.prototype.border = 0; - -/** - * Variable: ordered - * - * Specifies if the display should reflect the order of the cells in - * the model. Default is true. This has precendence over - * <keepEdgesInBackground> and <keepEdgesInForeground>. - */ -mxGraph.prototype.ordered = true; - -/** - * Variable: keepEdgesInForeground - * - * Specifies if edges should appear in the foreground regardless of their - * order in the model. This has precendence over <keepEdgeInBackground>, - * but not over <ordered>. Default is false. - */ -mxGraph.prototype.keepEdgesInForeground = false; - -/** - * Variable: keepEdgesInBackground - * - * Specifies if edges should appear in the background regardless of their - * order in the model. <ordered> and <keepEdgesInForeground> have - * precedence over this setting. Default is true. - */ -mxGraph.prototype.keepEdgesInBackground = true; - -/** - * Variable: allowNegativeCoordinates - * - * Specifies if negative coordinates for vertices are allowed. Default is true. - */ -mxGraph.prototype.allowNegativeCoordinates = true; - -/** - * Variable: constrainChildren - * - * Specifies the return value for <isConstrainChildren>. Default is - * true. - */ -mxGraph.prototype.constrainChildren = true; - -/** - * Variable: extendParents - * - * Specifies if a parent should contain the child bounds after a resize of - * the child. Default is true. - */ -mxGraph.prototype.extendParents = true; - -/** - * Variable: extendParentsOnAdd - * - * Specifies if parents should be extended according to the <extendParents> - * switch if cells are added. Default is true. - */ -mxGraph.prototype.extendParentsOnAdd = true; - -/** - * Variable: collapseToPreferredSize - * - * Specifies if the cell size should be changed to the preferred size when - * a cell is first collapsed. Default is true. - */ -mxGraph.prototype.collapseToPreferredSize = true; - -/** - * Variable: zoomFactor - * - * Specifies the factor used for <zoomIn> and <zoomOut>. Default is 1.2 - * (120%). - */ -mxGraph.prototype.zoomFactor = 1.2; - -/** - * Variable: keepSelectionVisibleOnZoom - * - * Specifies if the viewport should automatically contain the selection cells - * after a zoom operation. Default is false. - */ -mxGraph.prototype.keepSelectionVisibleOnZoom = false; - -/** - * Variable: centerZoom - * - * Specifies if the zoom operations should go into the center of the actual - * diagram rather than going from top, left. Default is true. - */ -mxGraph.prototype.centerZoom = true; - -/** - * Variable: resetViewOnRootChange - * - * Specifies if the scale and translate should be reset if the root changes in - * the model. Default is true. - */ -mxGraph.prototype.resetViewOnRootChange = true; - -/** - * Variable: resetEdgesOnResize - * - * Specifies if edge control points should be reset after the resize of a - * connected cell. Default is false. - */ -mxGraph.prototype.resetEdgesOnResize = false; - -/** - * Variable: resetEdgesOnMove - * - * Specifies if edge control points should be reset after the move of a - * connected cell. Default is false. - */ -mxGraph.prototype.resetEdgesOnMove = false; - -/** - * Variable: resetEdgesOnConnect - * - * Specifies if edge control points should be reset after the the edge has been - * reconnected. Default is true. - */ -mxGraph.prototype.resetEdgesOnConnect = true; - -/** - * Variable: allowLoops - * - * Specifies if loops (aka self-references) are allowed. Default is false. - */ -mxGraph.prototype.allowLoops = false; - -/** - * Variable: defaultLoopStyle - * - * <mxEdgeStyle> to be used for loops. This is a fallback for loops if the - * <mxConstants.STYLE_LOOP> is undefined. Default is <mxEdgeStyle.Loop>. - */ -mxGraph.prototype.defaultLoopStyle = mxEdgeStyle.Loop; - -/** - * Variable: multigraph - * - * Specifies if multiple edges in the same direction between the same pair of - * vertices are allowed. Default is true. - */ -mxGraph.prototype.multigraph = true; - -/** - * Variable: connectableEdges - * - * Specifies if edges are connectable. Default is false. This overrides the - * connectable field in edges. - */ -mxGraph.prototype.connectableEdges = false; - -/** - * Variable: allowDanglingEdges - * - * Specifies if edges with disconnected terminals are allowed in the graph. - * Default is true. - */ -mxGraph.prototype.allowDanglingEdges = true; - -/** - * Variable: cloneInvalidEdges - * - * Specifies if edges that are cloned should be validated and only inserted - * if they are valid. Default is true. - */ -mxGraph.prototype.cloneInvalidEdges = false; - -/** - * Variable: disconnectOnMove - * - * Specifies if edges should be disconnected from their terminals when they - * are moved. Default is true. - */ -mxGraph.prototype.disconnectOnMove = true; - -/** - * Variable: labelsVisible - * - * Specifies if labels should be visible. This is used in <getLabel>. Default - * is true. - */ -mxGraph.prototype.labelsVisible = true; - -/** - * Variable: htmlLabels - * - * Specifies the return value for <isHtmlLabel>. Default is false. - */ -mxGraph.prototype.htmlLabels = false; - -/** - * Variable: swimlaneSelectionEnabled - * - * Specifies if swimlanes should be selectable via the content if the - * mouse is released. Default is true. - */ -mxGraph.prototype.swimlaneSelectionEnabled = true; - -/** - * Variable: swimlaneNesting - * - * Specifies if nesting of swimlanes is allowed. Default is true. - */ -mxGraph.prototype.swimlaneNesting = true; - -/** - * Variable: swimlaneIndicatorColorAttribute - * - * The attribute used to find the color for the indicator if the indicator - * color is set to 'swimlane'. Default is <mxConstants.STYLE_FILLCOLOR>. - */ -mxGraph.prototype.swimlaneIndicatorColorAttribute = mxConstants.STYLE_FILLCOLOR; - -/** - * Variable: imageBundles - * - * Holds the list of image bundles. - */ -mxGraph.prototype.imageBundles = null; - -/** - * Variable: minFitScale - * - * Specifies the minimum scale to be applied in <fit>. Default is 0.1. Set this - * to null to allow any value. - */ -mxGraph.prototype.minFitScale = 0.1; - -/** - * Variable: maxFitScale - * - * Specifies the maximum scale to be applied in <fit>. Default is 8. Set this - * to null to allow any value. - */ -mxGraph.prototype.maxFitScale = 8; - -/** - * Variable: panDx - * - * Current horizontal panning value. Default is 0. - */ -mxGraph.prototype.panDx = 0; - -/** - * Variable: panDy - * - * Current vertical panning value. Default is 0. - */ -mxGraph.prototype.panDy = 0; - -/** - * Variable: collapsedImage - * - * Specifies the <mxImage> to indicate a collapsed state. - * Default value is mxClient.imageBasePath + '/collapsed.gif' - */ -mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9); - -/** - * Variable: expandedImage - * - * Specifies the <mxImage> to indicate a expanded state. - * Default value is mxClient.imageBasePath + '/expanded.gif' - */ -mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9); - -/** - * Variable: warningImage - * - * Specifies the <mxImage> for the image to be used to display a warning - * overlay. See <setCellWarning>. Default value is mxClient.imageBasePath + - * '/warning'. The extension for the image depends on the platform. It is - * '.png' on the Mac and '.gif' on all other platforms. - */ -mxGraph.prototype.warningImage = new mxImage(mxClient.imageBasePath + '/warning'+ - ((mxClient.IS_MAC) ? '.png' : '.gif'), 16, 16); - -/** - * Variable: alreadyConnectedResource - * - * Specifies the resource key for the error message to be displayed in - * non-multigraphs when two vertices are already connected. If the resource - * for this key does not exist then the value is used as the error message. - * Default is 'alreadyConnected'. - */ -mxGraph.prototype.alreadyConnectedResource = (mxClient.language != 'none') ? 'alreadyConnected' : ''; - -/** - * Variable: containsValidationErrorsResource - * - * Specifies the resource key for the warning message to be displayed when - * a collapsed cell contains validation errors. If the resource for this - * key does not exist then the value is used as the warning message. - * Default is 'containsValidationErrors'. - */ -mxGraph.prototype.containsValidationErrorsResource = (mxClient.language != 'none') ? 'containsValidationErrors' : ''; - -/** - * Variable: collapseExpandResource - * - * Specifies the resource key for the tooltip on the collapse/expand icon. - * If the resource for this key does not exist then the value is used as - * the tooltip. Default is 'collapse-expand'. - */ -mxGraph.prototype.collapseExpandResource = (mxClient.language != 'none') ? 'collapse-expand' : ''; - -/** - * Function: init - * - * Initializes the <container> and creates the respective datastructures. - * - * Parameters: - * - * container - DOM node that will contain the graph display. - */ - mxGraph.prototype.init = function(container) - { - this.container = container; - - // Initializes the in-place editor - this.cellEditor = this.createCellEditor(); - - // Initializes the container using the view - this.view.init(); - - // Updates the size of the container for the current graph - this.sizeDidChange(); - - // Automatic deallocation of memory - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', mxUtils.bind(this, function() - { - this.destroy(); - })); - - // Disable shift-click for text - mxEvent.addListener(container, 'selectstart', - mxUtils.bind(this, function() - { - return this.isEditing(); - }) - ); - } -}; - -/** - * Function: createHandlers - * - * Creates the tooltip-, panning-, connection- and graph-handler (in this - * order). This is called in the constructor before <init> is called. - */ -mxGraph.prototype.createHandlers = function(container) -{ - this.tooltipHandler = new mxTooltipHandler(this); - this.tooltipHandler.setEnabled(false); - this.panningHandler = new mxPanningHandler(this); - this.panningHandler.panningEnabled = false; - this.selectionCellsHandler = new mxSelectionCellsHandler(this); - this.connectionHandler = new mxConnectionHandler(this); - this.connectionHandler.setEnabled(false); - this.graphHandler = new mxGraphHandler(this); -}; - -/** - * Function: createSelectionModel - * - * Creates a new <mxGraphSelectionModel> to be used in this graph. - */ -mxGraph.prototype.createSelectionModel = function() -{ - return new mxGraphSelectionModel(this); -}; - -/** - * Function: createStylesheet - * - * Creates a new <mxGraphSelectionModel> to be used in this graph. - */ -mxGraph.prototype.createStylesheet = function() -{ - return new mxStylesheet(); -}; - -/** - * Function: createGraphView - * - * Creates a new <mxGraphView> to be used in this graph. - */ -mxGraph.prototype.createGraphView = function() -{ - return new mxGraphView(this); -}; - -/** - * Function: createCellRenderer - * - * Creates a new <mxCellRenderer> to be used in this graph. - */ -mxGraph.prototype.createCellRenderer = function() -{ - return new mxCellRenderer(); -}; - -/** - * Function: createCellEditor - * - * Creates a new <mxCellEditor> to be used in this graph. - */ -mxGraph.prototype.createCellEditor = function() -{ - return new mxCellEditor(this); -}; - -/** - * Function: getModel - * - * Returns the <mxGraphModel> that contains the cells. - */ -mxGraph.prototype.getModel = function() -{ - return this.model; -}; - -/** - * Function: getView - * - * Returns the <mxGraphView> that contains the <mxCellStates>. - */ -mxGraph.prototype.getView = function() -{ - return this.view; -}; - -/** - * Function: getStylesheet - * - * Returns the <mxStylesheet> that defines the style. - */ -mxGraph.prototype.getStylesheet = function() -{ - return this.stylesheet; -}; - -/** - * Function: setStylesheet - * - * Sets the <mxStylesheet> that defines the style. - */ -mxGraph.prototype.setStylesheet = function(stylesheet) -{ - this.stylesheet = stylesheet; -}; - -/** - * Function: getSelectionModel - * - * Returns the <mxGraphSelectionModel> that contains the selection. - */ -mxGraph.prototype.getSelectionModel = function() -{ - return this.selectionModel; -}; - -/** - * Function: setSelectionModel - * - * Sets the <mxSelectionModel> that contains the selection. - */ -mxGraph.prototype.setSelectionModel = function(selectionModel) -{ - this.selectionModel = selectionModel; -}; - -/** - * Function: getSelectionCellsForChanges - * - * Returns the cells to be selected for the given array of changes. - */ -mxGraph.prototype.getSelectionCellsForChanges = function(changes) -{ - var cells = []; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change.constructor != mxRootChange) - { - var cell = null; - - if (change instanceof mxChildChange && change.previous == null) - { - cell = change.child; - } - else if (change.cell != null && change.cell instanceof mxCell) - { - cell = change.cell; - } - - if (cell != null && mxUtils.indexOf(cells, cell) < 0) - { - cells.push(cell); - } - } - } - - return this.getModel().getTopmostCells(cells); -}; - -/** - * Function: graphModelChanged - * - * Called when the graph model changes. Invokes <processChange> on each - * item of the given array to update the view accordingly. - * - * Parameters: - * - * changes - Array that contains the individual changes. - */ -mxGraph.prototype.graphModelChanged = function(changes) -{ - for (var i = 0; i < changes.length; i++) - { - this.processChange(changes[i]); - } - - this.removeSelectionCells(this.getRemovedCellsForChanges(changes)); - - this.view.validate(); - this.sizeDidChange(); -}; - -/** - * Function: getRemovedCellsForChanges - * - * Returns the cells that have been removed from the model. - */ -mxGraph.prototype.getRemovedCellsForChanges = function(changes) -{ - var result = []; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - // Resets the view settings, removes all cells and clears - // the selection if the root changes. - if (change instanceof mxRootChange) - { - break; - } - else if (change instanceof mxChildChange) - { - if (change.previous != null && change.parent == null) - { - result = result.concat(this.model.getDescendants(change.child)); - } - } - else if (change instanceof mxVisibleChange) - { - result = result.concat(this.model.getDescendants(change.cell)); - } - } - - return result; -}; - -/** - * Function: processChange - * - * Processes the given change and invalidates the respective cached data - * in <view>. This fires a <root> event if the root has changed in the - * model. - * - * Parameters: - * - * change - Object that represents the change on the model. - */ -mxGraph.prototype.processChange = function(change) -{ - // Resets the view settings, removes all cells and clears - // the selection if the root changes. - if (change instanceof mxRootChange) - { - this.clearSelection(); - this.removeStateForCell(change.previous); - - if (this.resetViewOnRootChange) - { - this.view.scale = 1; - this.view.translate.x = 0; - this.view.translate.y = 0; - } - - this.fireEvent(new mxEventObject(mxEvent.ROOT)); - } - - // Adds or removes a child to the view by online invaliding - // the minimal required portions of the cache, namely, the - // old and new parent and the child. - else if (change instanceof mxChildChange) - { - var newParent = this.model.getParent(change.child); - - if (newParent != null) - { - // Flags the cell for updating the order in the renderer - this.view.invalidate(change.child, true, false, change.previous != null); - } - else - { - this.removeStateForCell(change.child); - - // Handles special case of current root of view being removed - if (this.view.currentRoot == change.child) - { - this.home(); - } - } - - if (newParent != change.previous) - { - // Refreshes the collapse/expand icons on the parents - if (newParent != null) - { - this.view.invalidate(newParent, false, false); - } - - if (change.previous != null) - { - this.view.invalidate(change.previous, false, false); - } - } - } - - // Handles two special cases where the shape does not need to be - // recreated from scratch, it only need to be invalidated. - else if (change instanceof mxTerminalChange || - change instanceof mxGeometryChange) - { - this.view.invalidate(change.cell); - } - - // Handles two special cases where only the shape, but no - // descendants need to be recreated - else if (change instanceof mxValueChange) - { - this.view.invalidate(change.cell, false, false); - } - - // Requires a new mxShape in JavaScript - else if (change instanceof mxStyleChange) - { - this.view.invalidate(change.cell, true, true, false); - this.view.removeState(change.cell); - } - - // Removes the state from the cache by default - else if (change.cell != null && - change.cell instanceof mxCell) - { - this.removeStateForCell(change.cell); - } -}; - -/** - * Function: removeStateForCell - * - * Removes all cached information for the given cell and its descendants. - * This is called when a cell was removed from the model. - * - * Paramters: - * - * cell - <mxCell> that was removed from the model. - */ -mxGraph.prototype.removeStateForCell = function(cell) -{ - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.removeStateForCell(this.model.getChildAt(cell, i)); - } - - this.view.removeState(cell); -}; - -/** - * Group: Overlays - */ - -/** - * Function: addCellOverlay - * - * Adds an <mxCellOverlay> for the specified cell. This method fires an - * <addoverlay> event and returns the new <mxCellOverlay>. - * - * Parameters: - * - * cell - <mxCell> to add the overlay for. - * overlay - <mxCellOverlay> to be added for the cell. - */ -mxGraph.prototype.addCellOverlay = function(cell, overlay) -{ - if (cell.overlays == null) - { - cell.overlays = []; - } - - cell.overlays.push(overlay); - - var state = this.view.getState(cell); - - // Immediately updates the cell display if the state exists - if (state != null) - { - this.cellRenderer.redraw(state); - } - - this.fireEvent(new mxEventObject(mxEvent.ADD_OVERLAY, - 'cell', cell, 'overlay', overlay)); - - return overlay; -}; - -/** - * Function: getCellOverlays - * - * Returns the array of <mxCellOverlays> for the given cell or null, if - * no overlays are defined. - * - * Parameters: - * - * cell - <mxCell> whose overlays should be returned. - */ -mxGraph.prototype.getCellOverlays = function(cell) -{ - return cell.overlays; -}; - -/** - * Function: removeCellOverlay - * - * Removes and returns the given <mxCellOverlay> from the given cell. This - * method fires a <removeoverlay> event. If no overlay is given, then all - * overlays are removed using <removeOverlays>. - * - * Parameters: - * - * cell - <mxCell> whose overlay should be removed. - * overlay - Optional <mxCellOverlay> to be removed. - */ -mxGraph.prototype.removeCellOverlay = function(cell, overlay) -{ - if (overlay == null) - { - this.removeCellOverlays(cell); - } - else - { - var index = mxUtils.indexOf(cell.overlays, overlay); - - if (index >= 0) - { - cell.overlays.splice(index, 1); - - if (cell.overlays.length == 0) - { - cell.overlays = null; - } - - // Immediately updates the cell display if the state exists - var state = this.view.getState(cell); - - if (state != null) - { - this.cellRenderer.redraw(state); - } - - this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY, - 'cell', cell, 'overlay', overlay)); - } - else - { - overlay = null; - } - } - - return overlay; -}; - -/** - * Function: removeCellOverlays - * - * Removes all <mxCellOverlays> from the given cell. This method - * fires a <removeoverlay> event for each <mxCellOverlay> and returns - * the array of <mxCellOverlays> that was removed from the cell. - * - * Parameters: - * - * cell - <mxCell> whose overlays should be removed - */ -mxGraph.prototype.removeCellOverlays = function(cell) -{ - var overlays = cell.overlays; - - if (overlays != null) - { - cell.overlays = null; - - // Immediately updates the cell display if the state exists - var state = this.view.getState(cell); - - if (state != null) - { - this.cellRenderer.redraw(state); - } - - for (var i = 0; i < overlays.length; i++) - { - this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY, - 'cell', cell, 'overlay', overlays[i])); - } - } - - return overlays; -}; - -/** - * Function: clearCellOverlays - * - * Removes all <mxCellOverlays> in the graph for the given cell and all its - * descendants. If no cell is specified then all overlays are removed from - * the graph. This implementation uses <removeCellOverlays> to remove the - * overlays from the individual cells. - * - * Parameters: - * - * cell - Optional <mxCell> that represents the root of the subtree to - * remove the overlays from. Default is the root in the model. - */ -mxGraph.prototype.clearCellOverlays = function(cell) -{ - cell = (cell != null) ? cell : this.model.getRoot(); - this.removeCellOverlays(cell); - - // Recursively removes all overlays from the children - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(cell, i); - this.clearCellOverlays(child); // recurse - } -}; - -/** - * Function: setCellWarning - * - * Creates an overlay for the given cell using the warning and image or - * <warningImage> and returns the new <mxCellOverlay>. The warning is - * displayed as a tooltip in a red font and may contain HTML markup. If - * the warning is null or a zero length string, then all overlays are - * removed from the cell. - * - * Example: - * - * (code) - * graph.setCellWarning(cell, '<b>Warning:</b>: Hello, World!'); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose warning should be set. - * warning - String that represents the warning to be displayed. - * img - Optional <mxImage> to be used for the overlay. Default is - * <warningImage>. - * isSelect - Optional boolean indicating if a click on the overlay - * should select the corresponding cell. Default is false. - */ -mxGraph.prototype.setCellWarning = function(cell, warning, img, isSelect) -{ - if (warning != null && warning.length > 0) - { - img = (img != null) ? img : this.warningImage; - - // Creates the overlay with the image and warning - var overlay = new mxCellOverlay(img, - '<font color=red>'+warning+'</font>'); - - // Adds a handler for single mouseclicks to select the cell - if (isSelect) - { - overlay.addListener(mxEvent.CLICK, - mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.setSelectionCell(cell); - } - }) - ); - } - - // Sets and returns the overlay in the graph - return this.addCellOverlay(cell, overlay); - } - else - { - this.removeCellOverlays(cell); - } - - return null; -}; - -/** - * Group: In-place editing - */ - -/** - * Function: startEditing - * - * Calls <startEditingAtCell> using the given cell or the first selection - * cell. - * - * Parameters: - * - * evt - Optional mouse event that triggered the editing. - */ -mxGraph.prototype.startEditing = function(evt) -{ - this.startEditingAtCell(null, evt); -}; - -/** - * Function: startEditingAtCell - * - * Fires a <startEditing> event and invokes <mxCellEditor.startEditing> - * on <editor>. - * - * Parameters: - * - * cell - <mxCell> to start the in-place editor for. - * evt - Optional mouse event that triggered the editing. - */ -mxGraph.prototype.startEditingAtCell = function(cell, evt) -{ - if (cell == null) - { - cell = this.getSelectionCell(); - - if (cell != null && !this.isCellEditable(cell)) - { - cell = null; - } - } - - if (cell != null) - { - this.fireEvent(new mxEventObject(mxEvent.START_EDITING, - 'cell', cell, 'event', evt)); - this.cellEditor.startEditing(cell, evt); - } -}; - -/** - * Function: getEditingValue - * - * Returns the initial value for in-place editing. This implementation - * returns <convertValueToString> for the given cell. If this function is - * overridden, then <mxGraphModel.valueForCellChanged> should take care - * of correctly storing the actual new value inside the user object. - * - * Parameters: - * - * cell - <mxCell> for which the initial editing value should be returned. - * evt - Optional mouse event that triggered the editor. - */ -mxGraph.prototype.getEditingValue = function(cell, evt) -{ - return this.convertValueToString(cell); -}; - -/** - * Function: stopEditing - * - * Stops the current editing. - * - * Parameters: - * - * cancel - Boolean that specifies if the current editing value - * should be stored. - */ -mxGraph.prototype.stopEditing = function(cancel) -{ - this.cellEditor.stopEditing(cancel); -}; - -/** - * Function: labelChanged - * - * Sets the label of the specified cell to the given value using - * <cellLabelChanged> and fires <mxEvent.LABEL_CHANGED> while the - * transaction is in progress. Returns the cell whose label was changed. - * - * Parameters: - * - * cell - <mxCell> whose label should be changed. - * value - New label to be assigned. - * evt - Optional event that triggered the change. - */ -mxGraph.prototype.labelChanged = function(cell, value, evt) -{ - this.model.beginUpdate(); - try - { - this.cellLabelChanged(cell, value, this.isAutoSizeCell(cell)); - this.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED, - 'cell', cell, 'value', value, 'event', evt)); - } - finally - { - this.model.endUpdate(); - } - - return cell; -}; - -/** - * Function: cellLabelChanged - * - * Sets the new label for a cell. If autoSize is true then - * <cellSizeUpdated> will be called. - * - * In the following example, the function is extended to map changes to - * attributes in an XML node, as shown in <convertValueToString>. - * Alternatively, the handling of this can be implemented as shown in - * <mxGraphModel.valueForCellChanged> without the need to clone the - * user object. - * - * (code) - * var graphCellLabelChanged = graph.cellLabelChanged; - * graph.cellLabelChanged = function(cell, newValue, autoSize) - * { - * // Cloned for correct undo/redo - * var elt = cell.value.cloneNode(true); - * elt.setAttribute('label', newValue); - * - * newValue = elt; - * graphCellLabelChanged.apply(this, arguments); - * }; - * (end) - * - * Parameters: - * - * cell - <mxCell> whose label should be changed. - * value - New label to be assigned. - * autoSize - Boolean that specifies if <cellSizeUpdated> should be called. - */ -mxGraph.prototype.cellLabelChanged = function(cell, value, autoSize) -{ - this.model.beginUpdate(); - try - { - this.model.setValue(cell, value); - - if (autoSize) - { - this.cellSizeUpdated(cell, false); - } - } - finally - { - this.model.endUpdate(); - } -}; - -/** - * Group: Event processing - */ - -/** - * Function: escape - * - * Processes an escape keystroke. - * - * Parameters: - * - * evt - Mouseevent that represents the keystroke. - */ -mxGraph.prototype.escape = function(evt) -{ - this.stopEditing(true); - this.connectionHandler.reset(); - this.graphHandler.reset(); - - // Cancels all cell-based editing - var cells = this.getSelectionCells(); - - for (var i = 0; i < cells.length; i++) - { - var state = this.view.getState(cells[i]); - - if (state != null && state.handler != null) - { - state.handler.reset(); - } - } -}; - -/** - * Function: click - * - * Processes a singleclick on an optional cell and fires a <click> event. - * The click event is fired initially. If the graph is enabled and the - * event has not been consumed, then the cell is selected using - * <selectCellForEvent> or the selection is cleared using - * <clearSelection>. The events consumed state is set to true if the - * corresponding <mxMouseEvent> has been consumed. - * - * Parameters: - * - * me - <mxMouseEvent> that represents the single click. - */ -mxGraph.prototype.click = function(me) -{ - var evt = me.getEvent(); - var cell = me.getCell(); - var mxe = new mxEventObject(mxEvent.CLICK, 'event', evt, 'cell', cell); - - if (me.isConsumed()) - { - mxe.consume(); - } - - this.fireEvent(mxe); - - // Handles the event if it has not been consumed - if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed()) - { - if (cell != null) - { - this.selectCellForEvent(cell, evt); - } - else - { - var swimlane = null; - - if (this.isSwimlaneSelectionEnabled()) - { - // Gets the swimlane at the location (includes - // content area of swimlanes) - swimlane = this.getSwimlaneAt(me.getGraphX(), me.getGraphY()); - } - - // Selects the swimlane and consumes the event - if (swimlane != null) - { - this.selectCellForEvent(swimlane, evt); - } - - // Ignores the event if the control key is pressed - else if (!this.isToggleEvent(evt)) - { - this.clearSelection(); - } - } - } -}; - -/** - * Function: dblClick - * - * Processes a doubleclick on an optional cell and fires a <dblclick> - * event. The event is fired initially. If the graph is enabled and the - * event has not been consumed, then <edit> is called with the given - * cell. The event is ignored if no cell was specified. - * - * Example for overriding this method. - * - * (code) - * graph.dblClick = function(evt, cell) - * { - * var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell); - * this.fireEvent(mxe); - * - * if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed()) - * { - * mxUtils.alert('Hello, World!'); - * mxe.consume(); - * } - * } - * (end) - * - * Example listener for this event. - * - * (code) - * graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt) - * { - * var cell = evt.getProperty('cell'); - * // do something with the cell... - * }); - * (end) - * - * Parameters: - * - * evt - Mouseevent that represents the doubleclick. - * cell - Optional <mxCell> under the mousepointer. - */ -mxGraph.prototype.dblClick = function(evt, cell) -{ - var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell); - this.fireEvent(mxe); - - // Handles the event if it has not been consumed - if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && - cell != null && this.isCellEditable(cell)) - { - this.startEditingAtCell(cell, evt); - } -}; - -/** - * Function: scrollPointToVisible - * - * Scrolls the graph to the given point, extending the graph container if - * specified. - */ -mxGraph.prototype.scrollPointToVisible = function(x, y, extend, border) -{ - if (!this.timerAutoScroll && (this.ignoreScrollbars || mxUtils.hasScrollbars(this.container))) - { - var c = this.container; - border = (border != null) ? border : 20; - - if (x >= c.scrollLeft && y >= c.scrollTop && x <= c.scrollLeft + c.clientWidth && - y <= c.scrollTop + c.clientHeight) - { - var dx = c.scrollLeft + c.clientWidth - x; - - if (dx < border) - { - var old = c.scrollLeft; - c.scrollLeft += border - dx; - - // Automatically extends the canvas size to the bottom, right - // if the event is outside of the canvas and the edge of the - // canvas has been reached. Notes: Needs fix for IE. - if (extend && old == c.scrollLeft) - { - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - var width = this.container.scrollWidth + border - dx; - - // Updates the clipping region. This is an expensive - // operation that should not be executed too often. - root.setAttribute('width', width); - } - else - { - var width = Math.max(c.clientWidth, c.scrollWidth) + border - dx; - var canvas = this.view.getCanvas(); - canvas.style.width = width + 'px'; - } - - c.scrollLeft += border - dx; - } - } - else - { - dx = x - c.scrollLeft; - - if (dx < border) - { - c.scrollLeft -= border - dx; - } - } - - var dy = c.scrollTop + c.clientHeight - y; - - if (dy < border) - { - var old = c.scrollTop; - c.scrollTop += border - dy; - - if (old == c.scrollTop && extend) - { - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - var height = this.container.scrollHeight + border - dy; - - // Updates the clipping region. This is an expensive - // operation that should not be executed too often. - root.setAttribute('height', height); - } - else - { - var height = Math.max(c.clientHeight, c.scrollHeight) + border - dy; - var canvas = this.view.getCanvas(); - canvas.style.height = height + 'px'; - } - - c.scrollTop += border - dy; - } - } - else - { - dy = y - c.scrollTop; - - if (dy < border) - { - c.scrollTop -= border - dy; - } - } - } - } - else if (this.allowAutoPanning && !this.panningHandler.active) - { - if (this.panningManager == null) - { - this.panningManager = this.createPanningManager(); - } - - this.panningManager.panTo(x + this.panDx, y + this.panDy); - } -}; - - -/** - * Function: createPanningManager - * - * Creates and returns an <mxPanningManager>. - */ -mxGraph.prototype.createPanningManager = function() -{ - return new mxPanningManager(this); -}; - -/** - * Function: getBorderSizes - * - * Returns the size of the border and padding on all four sides of the - * container. The left, top, right and bottom borders are stored in the x, y, - * width and height of the returned <mxRectangle>, respectively. - */ -mxGraph.prototype.getBorderSizes = function() -{ - // Helper function to handle string values for border widths (approx) - function parseBorder(value) - { - var result = 0; - - if (value == 'thin') - { - result = 2; - } - else if (value == 'medium') - { - result = 4; - } - else if (value == 'thick') - { - result = 6; - } - else - { - result = parseInt(value); - } - - if (isNaN(result)) - { - result = 0; - } - - return result; - } - - var style = mxUtils.getCurrentStyle(this.container); - var result = new mxRectangle(); - result.x = parseBorder(style.borderLeftWidth) + parseInt(style.paddingLeft || 0); - result.y = parseBorder(style.borderTopWidth) + parseInt(style.paddingTop || 0); - result.width = parseBorder(style.borderRightWidth) + parseInt(style.paddingRight || 0); - result.height = parseBorder(style.borderBottomWidth) + parseInt(style.paddingBottom || 0); - - return result; -}; - - -/** - * Function: getPreferredPageSize - * - * Returns the preferred size of the background page if <preferPageSize> is true. - */ -mxGraph.prototype.getPreferredPageSize = function(bounds, width, height) -{ - var scale = this.view.scale; - var tr = this.view.translate; - var fmt = this.pageFormat; - var ps = scale * this.pageScale; - var page = new mxRectangle(0, 0, fmt.width * ps, fmt.height * ps); - - var hCount = (this.pageBreaksVisible) ? Math.ceil(width / page.width) : 1; - var vCount = (this.pageBreaksVisible) ? Math.ceil(height / page.height) : 1; - - return new mxRectangle(0, 0, hCount * page.width + 2 + tr.x / scale, vCount * page.height + 2 + tr.y / scale); -}; - -/** - * Function: sizeDidChange - * - * Called when the size of the graph has changed. This implementation fires - * a <size> event after updating the clipping region of the SVG element in - * SVG-bases browsers. - */ -mxGraph.prototype.sizeDidChange = function() -{ - var bounds = this.getGraphBounds(); - - if (this.container != null) - { - var border = this.getBorder(); - - var width = Math.max(0, bounds.x + bounds.width + 1 + border); - var height = Math.max(0, bounds.y + bounds.height + 1 + border); - - if (this.minimumContainerSize != null) - { - width = Math.max(width, this.minimumContainerSize.width); - height = Math.max(height, this.minimumContainerSize.height); - } - - if (this.resizeContainer) - { - this.doResizeContainer(width, height); - } - - if (this.preferPageSize || (!mxClient.IS_IE && this.pageVisible)) - { - var size = this.getPreferredPageSize(bounds, width, height); - - if (size != null) - { - width = size.width; - height = size.height; - } - } - - if (this.minimumGraphSize != null) - { - width = Math.max(width, this.minimumGraphSize.width * this.view.scale); - height = Math.max(height, this.minimumGraphSize.height * this.view.scale); - } - - width = Math.ceil(width - 1); - height = Math.ceil(height - 1); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - - root.style.minWidth = Math.max(1, width) + 'px'; - root.style.minHeight = Math.max(1, height) + 'px'; - } - else - { - if (mxClient.IS_QUIRKS) - { - // Quirks mode has no minWidth/minHeight support - this.view.updateHtmlCanvasSize(Math.max(1, width), Math.max(1, height)); - } - else - { - this.view.canvas.style.minWidth = Math.max(1, width) + 'px'; - this.view.canvas.style.minHeight = Math.max(1, height) + 'px'; - } - } - - this.updatePageBreaks(this.pageBreaksVisible, width - 1, height - 1); - } - - this.fireEvent(new mxEventObject(mxEvent.SIZE, 'bounds', bounds)); -}; - -/** - * Function: doResizeContainer - * - * Resizes the container for the given graph width and height. - */ -mxGraph.prototype.doResizeContainer = function(width, height) -{ - // Fixes container size for different box models - if (mxClient.IS_IE) - { - if (mxClient.IS_QUIRKS) - { - var borders = this.getBorderSizes(); - - // max(2, ...) required for native IE8 in quirks mode - width += Math.max(2, borders.x + borders.width + 1); - height += Math.max(2, borders.y + borders.height + 1); - } - else if (document.documentMode >= 9) - { - width += 3; - height += 5; - } - else - { - width += 1; - height += 1; - } - } - else - { - height += 1; - } - - if (this.maximumContainerSize != null) - { - width = Math.min(this.maximumContainerSize.width, width); - height = Math.min(this.maximumContainerSize.height, height); - } - - this.container.style.width = Math.ceil(width) + 'px'; - this.container.style.height = Math.ceil(height) + 'px'; -}; - -/** - * Function: redrawPageBreaks - * - * Invokes from <sizeDidChange> to redraw the page breaks. - * - * Parameters: - * - * visible - Boolean that specifies if page breaks should be shown. - * width - Specifies the width of the container in pixels. - * height - Specifies the height of the container in pixels. - */ -mxGraph.prototype.updatePageBreaks = function(visible, width, height) -{ - var scale = this.view.scale; - var tr = this.view.translate; - var fmt = this.pageFormat; - var ps = scale * this.pageScale; - var bounds = new mxRectangle(scale * tr.x, scale * tr.y, - fmt.width * ps, fmt.height * ps); - - // Does not show page breaks if the scale is too small - visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist; - - // Draws page breaks independent of translate. To ignore - // the translate set bounds.x/y = 0. Note that modulo - // in JavaScript has a bug, so use mxUtils instead. - bounds.x = mxUtils.mod(bounds.x, bounds.width); - bounds.y = mxUtils.mod(bounds.y, bounds.height); - - var horizontalCount = (visible) ? Math.ceil((width - bounds.x) / bounds.width) : 0; - var verticalCount = (visible) ? Math.ceil((height - bounds.y) / bounds.height) : 0; - var right = width; - var bottom = height; - - if (this.horizontalPageBreaks == null && horizontalCount > 0) - { - this.horizontalPageBreaks = []; - } - - if (this.horizontalPageBreaks != null) - { - for (var i = 0; i <= horizontalCount; i++) - { - var pts = [new mxPoint(bounds.x + i * bounds.width, 1), - new mxPoint(bounds.x + i * bounds.width, bottom)]; - - if (this.horizontalPageBreaks[i] != null) - { - this.horizontalPageBreaks[i].scale = 1; - this.horizontalPageBreaks[i].points = pts; - this.horizontalPageBreaks[i].redraw(); - } - else - { - var pageBreak = new mxPolyline(pts, this.pageBreakColor, this.scale); - pageBreak.dialect = this.dialect; - pageBreak.isDashed = this.pageBreakDashed; - pageBreak.scale = scale; - pageBreak.crisp = true; - pageBreak.init(this.view.backgroundPane); - pageBreak.redraw(); - - this.horizontalPageBreaks[i] = pageBreak; - } - } - - for (var i = horizontalCount; i < this.horizontalPageBreaks.length; i++) - { - this.horizontalPageBreaks[i].destroy(); - } - - this.horizontalPageBreaks.splice(horizontalCount, this.horizontalPageBreaks.length - horizontalCount); - } - - if (this.verticalPageBreaks == null && verticalCount > 0) - { - this.verticalPageBreaks = []; - } - - if (this.verticalPageBreaks != null) - { - for (var i = 0; i <= verticalCount; i++) - { - var pts = [new mxPoint(1, bounds.y + i * bounds.height), - new mxPoint(right, bounds.y + i * bounds.height)]; - - if (this.verticalPageBreaks[i] != null) - { - this.verticalPageBreaks[i].scale = 1; - this.verticalPageBreaks[i].points = pts; - this.verticalPageBreaks[i].redraw(); - } - else - { - var pageBreak = new mxPolyline(pts, this.pageBreakColor, scale); - pageBreak.dialect = this.dialect; - pageBreak.isDashed = this.pageBreakDashed; - pageBreak.scale = scale; - pageBreak.crisp = true; - pageBreak.init(this.view.backgroundPane); - pageBreak.redraw(); - - this.verticalPageBreaks[i] = pageBreak; - } - } - - for (var i = verticalCount; i < this.verticalPageBreaks.length; i++) - { - this.verticalPageBreaks[i].destroy(); - } - - this.verticalPageBreaks.splice(verticalCount, this.verticalPageBreaks.length - verticalCount); - } -}; - -/** - * Group: Cell styles - */ - -/** - * Function: getCellStyle - * - * Returns an array of key, value pairs representing the cell style for the - * given cell. If no string is defined in the model that specifies the - * style, then the default style for the cell is returned or <EMPTY_ARRAY>, - * if not style can be found. Note: You should try and get the cell state - * for the given cell and use the cached style in the state before using - * this method. - * - * Parameters: - * - * cell - <mxCell> whose style should be returned as an array. - */ -mxGraph.prototype.getCellStyle = function(cell) -{ - var stylename = this.model.getStyle(cell); - var style = null; - - // Gets the default style for the cell - if (this.model.isEdge(cell)) - { - style = this.stylesheet.getDefaultEdgeStyle(); - } - else - { - style = this.stylesheet.getDefaultVertexStyle(); - } - - // Resolves the stylename using the above as the default - if (stylename != null) - { - style = this.postProcessCellStyle(this.stylesheet.getCellStyle(stylename, style)); - } - - // Returns a non-null value if no style can be found - if (style == null) - { - style = mxGraph.prototype.EMPTY_ARRAY; - } - - return style; -}; - -/** - * Function: postProcessCellStyle - * - * Tries to resolve the value for the image style in the image bundles and - * turns short data URIs as defined in mxImageBundle to data URIs as - * defined in RFC 2397 of the IETF. - */ -mxGraph.prototype.postProcessCellStyle = function(style) -{ - if (style != null) - { - var key = style[mxConstants.STYLE_IMAGE]; - var image = this.getImageFromBundles(key); - - if (image != null) - { - style[mxConstants.STYLE_IMAGE] = image; - } - else - { - image = key; - } - - // Converts short data uris to normal data uris - if (image != null && image.substring(0, 11) == "data:image/") - { - var comma = image.indexOf(','); - - if (comma > 0) - { - image = image.substring(0, comma) + ";base64," - + image.substring(comma + 1); - } - - style[mxConstants.STYLE_IMAGE] = image; - } - } - - return style; -}; - -/** - * Function: setCellStyle - * - * Sets the style of the specified cells. If no cells are given, then the - * selection cells are changed. - * - * Parameters: - * - * style - String representing the new style of the cells. - * cells - Optional array of <mxCells> to set the style for. Default is the - * selection cells. - */ -mxGraph.prototype.setCellStyle = function(style, cells) -{ - cells = cells || this.getSelectionCells(); - - if (cells != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - this.model.setStyle(cells[i], style); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: toggleCellStyle - * - * Toggles the boolean value for the given key in the style of the - * given cell. If no cell is specified then the selection cell is - * used. - * - * Parameter: - * - * key - String representing the key for the boolean value to be toggled. - * defaultValue - Optional boolean default value if no value is defined. - * Default is false. - * cell - Optional <mxCell> whose style should be modified. Default is - * the selection cell. - */ -mxGraph.prototype.toggleCellStyle = function(key, defaultValue, cell) -{ - cell = cell || this.getSelectionCell(); - - this.toggleCellStyles(key, defaultValue, [cell]); -}; - -/** - * Function: toggleCellStyles - * - * Toggles the boolean value for the given key in the style of the given - * cells. If no cells are specified, then the selection cells are used. For - * example, this can be used to toggle <mxConstants.STYLE_ROUNDED> or any - * other style with a boolean value. - * - * Parameter: - * - * key - String representing the key for the boolean value to be toggled. - * defaultValue - Optional boolean default value if no value is defined. - * Default is false. - * cells - Optional array of <mxCells> whose styles should be modified. - * Default is the selection cells. - */ -mxGraph.prototype.toggleCellStyles = function(key, defaultValue, cells) -{ - defaultValue = (defaultValue != null) ? defaultValue : false; - cells = cells || this.getSelectionCells(); - - if (cells != null && cells.length > 0) - { - var state = this.view.getState(cells[0]); - var style = (state != null) ? state.style : this.getCellStyle(cells[0]); - - if (style != null) - { - var val = (mxUtils.getValue(style, key, defaultValue)) ? 0 : 1; - this.setCellStyles(key, val, cells); - } - } -}; - -/** - * Function: setCellStyles - * - * Sets the key to value in the styles of the given cells. This will modify - * the existing cell styles in-place and override any existing assignment - * for the given key. If no cells are specified, then the selection cells - * are changed. If no value is specified, then the respective key is - * removed from the styles. - * - * Parameters: - * - * key - String representing the key to be assigned. - * value - String representing the new value for the key. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.setCellStyles = function(key, value, cells) -{ - cells = cells || this.getSelectionCells(); - mxUtils.setCellStyles(this.model, cells, key, value); -}; - -/** - * Function: toggleCellStyleFlags - * - * Toggles the given bit for the given key in the styles of the specified - * cells. - * - * Parameters: - * - * key - String representing the key to toggle the flag in. - * flag - Integer that represents the bit to be toggled. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.toggleCellStyleFlags = function(key, flag, cells) -{ - this.setCellStyleFlags(key, flag, null, cells); -}; - -/** - * Function: setCellStyleFlags - * - * Sets or toggles the given bit for the given key in the styles of the - * specified cells. - * - * Parameters: - * - * key - String representing the key to toggle the flag in. - * flag - Integer that represents the bit to be toggled. - * value - Boolean value to be used or null if the value should be toggled. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.setCellStyleFlags = function(key, flag, value, cells) -{ - cells = cells || this.getSelectionCells(); - - if (cells != null && cells.length > 0) - { - if (value == null) - { - var state = this.view.getState(cells[0]); - var style = (state != null) ? state.style : this.getCellStyle(cells[0]); - - if (style != null) - { - var current = parseInt(style[key] || 0); - value = !((current & flag) == flag); - } - } - - mxUtils.setCellStyleFlags(this.model, cells, key, flag, value); - } -}; - -/** - * Group: Cell alignment and orientation - */ - -/** - * Function: alignCells - * - * Aligns the given cells vertically or horizontally according to the given - * alignment using the optional parameter as the coordinate. - * - * Parameters: - * - * align - Specifies the alignment. Possible values are all constants in - * mxConstants with an ALIGN prefix. - * cells - Array of <mxCells> to be aligned. - * param - Optional coordinate for the alignment. - */ -mxGraph.prototype.alignCells = function(align, cells, param) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - if (cells != null && cells.length > 1) - { - // Finds the required coordinate for the alignment - if (param == null) - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null && !this.model.isEdge(cells[i])) - { - if (param == null) - { - if (align == mxConstants.ALIGN_CENTER) - { - param = geo.x + geo.width / 2; - break; - } - else if (align == mxConstants.ALIGN_RIGHT) - { - param = geo.x + geo.width; - } - else if (align == mxConstants.ALIGN_TOP) - { - param = geo.y; - } - else if (align == mxConstants.ALIGN_MIDDLE) - { - param = geo.y + geo.height / 2; - break; - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - param = geo.y + geo.height; - } - else - { - param = geo.x; - } - } - else - { - if (align == mxConstants.ALIGN_RIGHT) - { - param = Math.max(param, geo.x + geo.width); - } - else if (align == mxConstants.ALIGN_TOP) - { - param = Math.min(param, geo.y); - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - param = Math.max(param, geo.y + geo.height); - } - else - { - param = Math.min(param, geo.x); - } - } - } - } - } - - // Aligns the cells to the coordinate - if (param != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null && !this.model.isEdge(cells[i])) - { - geo = geo.clone(); - - if (align == mxConstants.ALIGN_CENTER) - { - geo.x = param - geo.width / 2; - } - else if (align == mxConstants.ALIGN_RIGHT) - { - geo.x = param - geo.width; - } - else if (align == mxConstants.ALIGN_TOP) - { - geo.y = param; - } - else if (align == mxConstants.ALIGN_MIDDLE) - { - geo.y = param - geo.height / 2; - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - geo.y = param - geo.height; - } - else - { - geo.x = param; - } - - this.model.setGeometry(cells[i], geo); - } - } - - this.fireEvent(new mxEventObject(mxEvent.ALIGN_CELLS, - 'align', align, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - } - - return cells; -}; - -/** - * Function: flipEdge - * - * Toggles the style of the given edge between null (or empty) and - * <alternateEdgeStyle>. This method fires <mxEvent.FLIP_EDGE> while the - * transaction is in progress. Returns the edge that was flipped. - * - * Here is an example that overrides this implementation to invert the - * value of <mxConstants.STYLE_ELBOW> without removing any existing styles. - * - * (code) - * graph.flipEdge = function(edge) - * { - * if (edge != null) - * { - * var state = this.view.getState(edge); - * var style = (state != null) ? state.style : this.getCellStyle(edge); - * - * if (style != null) - * { - * var elbow = mxUtils.getValue(style, mxConstants.STYLE_ELBOW, - * mxConstants.ELBOW_HORIZONTAL); - * var value = (elbow == mxConstants.ELBOW_HORIZONTAL) ? - * mxConstants.ELBOW_VERTICAL : mxConstants.ELBOW_HORIZONTAL; - * this.setCellStyles(mxConstants.STYLE_ELBOW, value, [edge]); - * } - * } - * }; - * (end) - * - * Parameters: - * - * edge - <mxCell> whose style should be changed. - */ -mxGraph.prototype.flipEdge = function(edge) -{ - if (edge != null && - this.alternateEdgeStyle != null) - { - this.model.beginUpdate(); - try - { - var style = this.model.getStyle(edge); - - if (style == null || style.length == 0) - { - this.model.setStyle(edge, this.alternateEdgeStyle); - } - else - { - this.model.setStyle(edge, null); - } - - // Removes all existing control points - this.resetEdge(edge); - this.fireEvent(new mxEventObject(mxEvent.FLIP_EDGE, 'edge', edge)); - } - finally - { - this.model.endUpdate(); - } - } - - return edge; -}; - -/** - * Function: addImageBundle - * - * Adds the specified <mxImageBundle>. - */ -mxGraph.prototype.addImageBundle = function(bundle) -{ - this.imageBundles.push(bundle); -}; - -/** - * Function: removeImageBundle - * - * Removes the specified <mxImageBundle>. - */ -mxGraph.prototype.removeImageBundle = function(bundle) -{ - var tmp = []; - - for (var i = 0; i < this.imageBundles.length; i++) - { - if (this.imageBundles[i] != bundle) - { - tmp.push(this.imageBundles[i]); - } - } - - this.imageBundles = tmp; -}; - -/** - * Function: getImageFromBundles - * - * Searches all <imageBundles> for the specified key and returns the value - * for the first match or null if the key is not found. - */ -mxGraph.prototype.getImageFromBundles = function(key) -{ - if (key != null) - { - for (var i = 0; i < this.imageBundles.length; i++) - { - var image = this.imageBundles[i].getImage(key); - - if (image != null) - { - return image; - } - } - } - - return null; -}; - -/** - * Group: Order - */ - -/** - * Function: orderCells - * - * Moves the given cells to the front or back. The change is carried out - * using <cellsOrdered>. This method fires <mxEvent.ORDER_CELLS> while the - * transaction is in progress. - * - * Parameters: - * - * back - Boolean that specifies if the cells should be moved to back. - * cells - Array of <mxCells> to move to the background. If null is - * specified then the selection cells are used. - */ - mxGraph.prototype.orderCells = function(back, cells) - { - if (cells == null) - { - cells = mxUtils.sortCells(this.getSelectionCells(), true); - } - - this.model.beginUpdate(); - try - { - this.cellsOrdered(cells, back); - this.fireEvent(new mxEventObject(mxEvent.ORDER_CELLS, - 'back', back, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; - }; - -/** - * Function: cellsOrdered - * - * Moves the given cells to the front or back. This method fires - * <mxEvent.CELLS_ORDERED> while the transaction is in progress. - * - * Parameters: - * - * cells - Array of <mxCells> whose order should be changed. - * back - Boolean that specifies if the cells should be moved to back. - */ - mxGraph.prototype.cellsOrdered = function(cells, back) - { - if (cells != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var parent = this.model.getParent(cells[i]); - - if (back) - { - this.model.add(parent, cells[i], i); - } - else - { - this.model.add(parent, cells[i], - this.model.getChildCount(parent) - 1); - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_ORDERED, - 'back', back, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Grouping - */ - -/** - * Function: groupCells - * - * Adds the cells into the given group. The change is carried out using - * <cellsAdded>, <cellsMoved> and <cellsResized>. This method fires - * <mxEvent.GROUP_CELLS> while the transaction is in progress. Returns the - * new group. A group is only created if there is at least one entry in the - * given array of cells. - * - * Parameters: - * - * group - <mxCell> that represents the target group. If null is specified - * then a new group is created using <createGroupCell>. - * border - Optional integer that specifies the border between the child - * area and the group bounds. Default is 0. - * cells - Optional array of <mxCells> to be grouped. If null is specified - * then the selection cells are used. - */ -mxGraph.prototype.groupCells = function(group, border, cells) -{ - if (cells == null) - { - cells = mxUtils.sortCells(this.getSelectionCells(), true); - } - - cells = this.getCellsForGroup(cells); - - if (group == null) - { - group = this.createGroupCell(cells); - } - - var bounds = this.getBoundsForGroup(group, cells, border); - - if (cells.length > 0 && bounds != null) - { - // Uses parent of group or previous parent of first child - var parent = this.model.getParent(group); - - if (parent == null) - { - parent = this.model.getParent(cells[0]); - } - - this.model.beginUpdate(); - try - { - // Checks if the group has a geometry and - // creates one if one does not exist - if (this.getCellGeometry(group) == null) - { - this.model.setGeometry(group, new mxGeometry()); - } - - // Adds the children into the group and moves - var index = this.model.getChildCount(group); - this.cellsAdded(cells, group, index, null, null, false, false); - this.cellsMoved(cells, -bounds.x, -bounds.y, false, true); - - // Adds the group into the parent and resizes - index = this.model.getChildCount(parent); - this.cellsAdded([group], parent, index, null, null, false); - this.cellsResized([group], [bounds]); - - this.fireEvent(new mxEventObject(mxEvent.GROUP_CELLS, - 'group', group, 'border', border, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - - return group; -}; - -/** - * Function: getCellsForGroup - * - * Returns the cells with the same parent as the first cell - * in the given array. - */ -mxGraph.prototype.getCellsForGroup = function(cells) -{ - var result = []; - - if (cells != null && cells.length > 0) - { - var parent = this.model.getParent(cells[0]); - result.push(cells[0]); - - // Filters selection cells with the same parent - for (var i = 1; i < cells.length; i++) - { - if (this.model.getParent(cells[i]) == parent) - { - result.push(cells[i]); - } - } - } - - return result; -}; - -/** - * Function: getBoundsForGroup - * - * Returns the bounds to be used for the given group and children. - */ -mxGraph.prototype.getBoundsForGroup = function(group, children, border) -{ - var result = this.getBoundingBoxFromGeometry(children); - - if (result != null) - { - if (this.isSwimlane(group)) - { - var size = this.getStartSize(group); - - result.x -= size.width; - result.y -= size.height; - result.width += size.width; - result.height += size.height; - } - - // Adds the border - result.x -= border; - result.y -= border; - result.width += 2 * border; - result.height += 2 * border; - } - - return result; -}; - -/** - * Function: createGroupCell - * - * Hook for creating the group cell to hold the given array of <mxCells> if - * no group cell was given to the <group> function. - * - * The following code can be used to set the style of new group cells. - * - * (code) - * var graphCreateGroupCell = graph.createGroupCell; - * graph.createGroupCell = function(cells) - * { - * var group = graphCreateGroupCell.apply(this, arguments); - * group.setStyle('group'); - * - * return group; - * }; - */ -mxGraph.prototype.createGroupCell = function(cells) -{ - var group = new mxCell(''); - group.setVertex(true); - group.setConnectable(false); - - return group; -}; - -/** - * Function: ungroupCells - * - * Ungroups the given cells by moving the children the children to their - * parents parent and removing the empty groups. Returns the children that - * have been removed from the groups. - * - * Parameters: - * - * cells - Array of cells to be ungrouped. If null is specified then the - * selection cells are used. - */ -mxGraph.prototype.ungroupCells = function(cells) -{ - var result = []; - - if (cells == null) - { - cells = this.getSelectionCells(); - - // Finds the cells with children - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.model.getChildCount(cells[i]) > 0) - { - tmp.push(cells[i]); - } - } - - cells = tmp; - } - - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var children = this.model.getChildren(cells[i]); - - if (children != null && children.length > 0) - { - children = children.slice(); - var parent = this.model.getParent(cells[i]); - var index = this.model.getChildCount(parent); - - this.cellsAdded(children, parent, index, null, null, true); - result = result.concat(children); - } - } - - this.cellsRemoved(this.addAllEdges(cells)); - this.fireEvent(new mxEventObject(mxEvent.UNGROUP_CELLS, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - - return result; -}; - -/** - * Function: removeCellsFromParent - * - * Removes the specified cells from their parents and adds them to the - * default parent. Returns the cells that were removed from their parents. - * - * Parameters: - * - * cells - Array of <mxCells> to be removed from their parents. - */ -mxGraph.prototype.removeCellsFromParent = function(cells) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - this.model.beginUpdate(); - try - { - var parent = this.getDefaultParent(); - var index = this.model.getChildCount(parent); - - this.cellsAdded(cells, parent, index, null, null, true); - this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS_FROM_PARENT, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: updateGroupBounds - * - * Updates the bounds of the given array of groups so that it includes - * all child vertices. - * - * Parameters: - * - * cells - The groups whose bounds should be updated. - * border - Optional border to be added in the group. Default is 0. - * moveGroup - Optional boolean that allows the group to be moved. Default - * is false. - */ -mxGraph.prototype.updateGroupBounds = function(cells, border, moveGroup) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - border = (border != null) ? border : 0; - moveGroup = (moveGroup != null) ? moveGroup : false; - - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null) - { - var children = this.getChildCells(cells[i]); - - if (children != null && children.length > 0) - { - var childBounds = this.getBoundingBoxFromGeometry(children); - - if (childBounds.width > 0 && childBounds.height > 0) - { - var size = (this.isSwimlane(cells[i])) ? - this.getStartSize(cells[i]) : new mxRectangle(); - - geo = geo.clone(); - - if (moveGroup) - { - geo.x += childBounds.x - size.width - border; - geo.y += childBounds.y - size.height - border; - } - - geo.width = childBounds.width + size.width + 2 * border; - geo.height = childBounds.height + size.height + 2 * border; - - this.model.setGeometry(cells[i], geo); - this.moveCells(children, -childBounds.x + size.width + border, - -childBounds.y + size.height + border); - } - } - } - } - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Group: Cell cloning, insertion and removal - */ - -/** - * Function: cloneCells - * - * Returns the clones for the given cells. If the terminal of an edge is - * not in the given array, then the respective end is assigned a terminal - * point and the terminal is removed. - * - * Parameters: - * - * cells - Array of <mxCells> to be cloned. - * allowInvalidEdges - Optional boolean that specifies if invalid edges - * should be cloned. Default is true. - */ -mxGraph.prototype.cloneCells = function(cells, allowInvalidEdges) -{ - allowInvalidEdges = (allowInvalidEdges != null) ? allowInvalidEdges : true; - var clones = null; - - if (cells != null) - { - // Creates a hashtable for cell lookups - var hash = new Object(); - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - tmp.push(cells[i]); - } - - if (tmp.length > 0) - { - var scale = this.view.scale; - var trans = this.view.translate; - clones = this.model.cloneCells(cells, true); - - for (var i = 0; i < cells.length; i++) - { - if (!allowInvalidEdges && this.model.isEdge(clones[i]) && - this.getEdgeValidationError(clones[i], - this.model.getTerminal(clones[i], true), - this.model.getTerminal(clones[i], false)) != null) - { - clones[i] = null; - } - else - { - var g = this.model.getGeometry(clones[i]); - - if (g != null) - { - var state = this.view.getState(cells[i]); - var pstate = this.view.getState( - this.model.getParent(cells[i])); - - if (state != null && pstate != null) - { - var dx = pstate.origin.x; - var dy = pstate.origin.y; - - if (this.model.isEdge(clones[i])) - { - var pts = state.absolutePoints; - - // Checks if the source is cloned or sets the terminal point - var src = this.model.getTerminal(cells[i], true); - var srcId = mxCellPath.create(src); - - while (src != null && hash[srcId] == null) - { - src = this.model.getParent(src); - srcId = mxCellPath.create(src); - } - - if (src == null) - { - g.setTerminalPoint( - new mxPoint(pts[0].x / scale - trans.x, - pts[0].y / scale - trans.y), true); - } - - // Checks if the target is cloned or sets the terminal point - var trg = this.model.getTerminal(cells[i], false); - var trgId = mxCellPath.create(trg); - - while (trg != null && hash[trgId] == null) - { - trg = this.model.getParent(trg); - trgId = mxCellPath.create(trg); - } - - if (trg == null) - { - var n = pts.length - 1; - g.setTerminalPoint( - new mxPoint(pts[n].x / scale - trans.x, - pts[n].y / scale - trans.y), false); - } - - // Translates the control points - var points = g.points; - - if (points != null) - { - for (var j = 0; j < points.length; j++) - { - points[j].x += dx; - points[j].y += dy; - } - } - } - else - { - g.x += dx; - g.y += dy; - } - } - } - } - } - } - else - { - clones = []; - } - } - - return clones; -}; - -/** - * Function: insertVertex - * - * Adds a new vertex into the given parent <mxCell> using value as the user - * object and the given coordinates as the <mxGeometry> of the new vertex. - * The id and style are used for the respective properties of the new - * <mxCell>, which is returned. - * - * When adding new vertices from a mouse event, one should take into - * account the offset of the graph container and the scale and translation - * of the view in order to find the correct unscaled, untranslated - * coordinates using <mxGraph.getPointForEvent> as follows: - * - * (code) - * var pt = graph.getPointForEvent(evt); - * var parent = graph.getDefaultParent(); - * graph.insertVertex(parent, null, - * 'Hello, World!', x, y, 220, 30); - * (end) - * - * For adding image cells, the style parameter can be assigned as - * - * (code) - * stylename;image=imageUrl - * (end) - * - * See <mxGraph> for more information on using images. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent of the new vertex. - * id - Optional string that defines the Id of the new vertex. - * value - Object to be used as the user object. - * x - Integer that defines the x coordinate of the vertex. - * y - Integer that defines the y coordinate of the vertex. - * width - Integer that defines the width of the vertex. - * height - Integer that defines the height of the vertex. - * style - Optional string that defines the cell style. - * relative - Optional boolean that specifies if the geometry is relative. - * Default is false. - */ -mxGraph.prototype.insertVertex = function(parent, id, value, - x, y, width, height, style, relative) -{ - var vertex = this.createVertex(parent, id, value, x, y, width, height, style, relative); - - return this.addCell(vertex, parent); -}; - -/** - * Function: createVertex - * - * Hook method that creates the new vertex for <insertVertex>. - */ -mxGraph.prototype.createVertex = function(parent, id, value, - x, y, width, height, style, relative) -{ - // Creates the geometry for the vertex - var geometry = new mxGeometry(x, y, width, height); - geometry.relative = (relative != null) ? relative : false; - - // Creates the vertex - var vertex = new mxCell(value, geometry, style); - vertex.setId(id); - vertex.setVertex(true); - vertex.setConnectable(true); - - return vertex; -}; - -/** - * Function: insertEdge - * - * Adds a new edge into the given parent <mxCell> using value as the user - * object and the given source and target as the terminals of the new edge. - * The id and style are used for the respective properties of the new - * <mxCell>, which is returned. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent of the new edge. - * id - Optional string that defines the Id of the new edge. - * value - JavaScript object to be used as the user object. - * source - <mxCell> that defines the source of the edge. - * target - <mxCell> that defines the target of the edge. - * style - Optional string that defines the cell style. - */ -mxGraph.prototype.insertEdge = function(parent, id, value, source, target, style) -{ - var edge = this.createEdge(parent, id, value, source, target, style); - - return this.addEdge(edge, parent, source, target); -}; - -/** - * Function: createEdge - * - * Hook method that creates the new edge for <insertEdge>. This - * implementation does not set the source and target of the edge, these - * are set when the edge is added to the model. - * - */ -mxGraph.prototype.createEdge = function(parent, id, value, source, target, style) -{ - // Creates the edge - var edge = new mxCell(value, new mxGeometry(), style); - edge.setId(id); - edge.setEdge(true); - edge.geometry.relative = true; - - return edge; -}; - -/** - * Function: addEdge - * - * Adds the edge to the parent and connects it to the given source and - * target terminals. This is a shortcut method. Returns the edge that was - * added. - * - * Parameters: - * - * edge - <mxCell> to be inserted into the given parent. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * source - Optional <mxCell> that represents the source terminal. - * target - Optional <mxCell> that represents the target terminal. - * index - Optional index to insert the cells at. Default is to append. - */ -mxGraph.prototype.addEdge = function(edge, parent, source, target, index) -{ - return this.addCell(edge, parent, index, source, target); -}; - -/** - * Function: addCell - * - * Adds the cell to the parent and connects it to the given source and - * target terminals. This is a shortcut method. Returns the cell that was - * added. - * - * Parameters: - * - * cell - <mxCell> to be inserted into the given parent. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * index - Optional index to insert the cells at. Default is to append. - * source - Optional <mxCell> that represents the source terminal. - * target - Optional <mxCell> that represents the target terminal. - */ -mxGraph.prototype.addCell = function(cell, parent, index, source, target) -{ - return this.addCells([cell], parent, index, source, target)[0]; -}; - -/** - * Function: addCells - * - * Adds the cells to the parent at the given index, connecting each cell to - * the optional source and target terminal. The change is carried out using - * <cellsAdded>. This method fires <mxEvent.ADD_CELLS> while the - * transaction is in progress. Returns the cells that were added. - * - * Parameters: - * - * cells - Array of <mxCells> to be inserted. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * index - Optional index to insert the cells at. Default is to append. - * source - Optional source <mxCell> for all inserted cells. - * target - Optional target <mxCell> for all inserted cells. - */ -mxGraph.prototype.addCells = function(cells, parent, index, source, target) -{ - if (parent == null) - { - parent = this.getDefaultParent(); - } - - if (index == null) - { - index = this.model.getChildCount(parent); - } - - this.model.beginUpdate(); - try - { - this.cellsAdded(cells, parent, index, source, target, false, true); - this.fireEvent(new mxEventObject(mxEvent.ADD_CELLS, 'cells', cells, - 'parent', parent, 'index', index, 'source', source, 'target', target)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsAdded - * - * Adds the specified cells to the given parent. This method fires - * <mxEvent.CELLS_ADDED> while the transaction is in progress. - */ -mxGraph.prototype.cellsAdded = function(cells, parent, index, source, target, absolute, constrain) -{ - if (cells != null && parent != null && index != null) - { - this.model.beginUpdate(); - try - { - var parentState = (absolute) ? this.view.getState(parent) : null; - var o1 = (parentState != null) ? parentState.origin : null; - var zero = new mxPoint(0, 0); - - for (var i = 0; i < cells.length; i++) - { - if (cells[i] == null) - { - index--; - } - else - { - var previous = this.model.getParent(cells[i]); - - // Keeps the cell at its absolute location - if (o1 != null && cells[i] != parent && parent != previous) - { - var oldState = this.view.getState(previous); - var o2 = (oldState != null) ? oldState.origin : zero; - var geo = this.model.getGeometry(cells[i]); - - if (geo != null) - { - var dx = o2.x - o1.x; - var dy = o2.y - o1.y; - - // FIXME: Cells should always be inserted first before any other edit - // to avoid forward references in sessions. - geo = geo.clone(); - geo.translate(dx, dy); - - if (!geo.relative && this.model.isVertex(cells[i]) && - !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - this.model.setGeometry(cells[i], geo); - } - } - - // Decrements all following indices - // if cell is already in parent - if (parent == previous) - { - index--; - } - - this.model.add(parent, cells[i], index + i); - - // Extends the parent - if (this.isExtendParentsOnAdd() && this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - - // Constrains the child - if (constrain == null || constrain) - { - this.constrainChild(cells[i]); - } - - // Sets the source terminal - if (source != null) - { - this.cellConnected(cells[i], source, true); - } - - // Sets the target terminal - if (target != null) - { - this.cellConnected(cells[i], target, false); - } - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_ADDED, 'cells', cells, - 'parent', parent, 'index', index, 'source', source, 'target', target, - 'absolute', absolute)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: removeCells - * - * Removes the given cells from the graph including all connected edges if - * includeEdges is true. The change is carried out using <cellsRemoved>. - * This method fires <mxEvent.REMOVE_CELLS> while the transaction is in - * progress. The removed cells are returned as an array. - * - * Parameters: - * - * cells - Array of <mxCells> to remove. If null is specified then the - * selection cells which are deletable are used. - * includeEdges - Optional boolean which specifies if all connected edges - * should be removed as well. Default is true. - */ -mxGraph.prototype.removeCells = function(cells, includeEdges) -{ - includeEdges = (includeEdges != null) ? includeEdges : true; - - if (cells == null) - { - cells = this.getDeletableCells(this.getSelectionCells()); - } - - // Adds all edges to the cells - if (includeEdges) - { - cells = this.getDeletableCells(this.addAllEdges(cells)); - } - - this.model.beginUpdate(); - try - { - this.cellsRemoved(cells); - this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS, - 'cells', cells, 'includeEdges', includeEdges)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsRemoved - * - * Removes the given cells from the model. This method fires - * <mxEvent.CELLS_REMOVED> while the transaction is in progress. - * - * Parameters: - * - * cells - Array of <mxCells> to remove. - */ -mxGraph.prototype.cellsRemoved = function(cells) -{ - if (cells != null && cells.length > 0) - { - var scale = this.view.scale; - var tr = this.view.translate; - - this.model.beginUpdate(); - try - { - // Creates hashtable for faster lookup - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - for (var i = 0; i < cells.length; i++) - { - // Disconnects edges which are not in cells - var edges = this.getConnections(cells[i]); - - for (var j = 0; j < edges.length; j++) - { - var id = mxCellPath.create(edges[j]); - - if (hash[id] == null) - { - var geo = this.model.getGeometry(edges[j]); - - if (geo != null) - { - var state = this.view.getState(edges[j]); - - if (state != null) - { - geo = geo.clone(); - var source = state.getVisibleTerminal(true) == cells[i]; - var pts = state.absolutePoints; - var n = (source) ? 0 : pts.length - 1; - - geo.setTerminalPoint( - new mxPoint(pts[n].x / scale - tr.x, - pts[n].y / scale - tr.y), source); - this.model.setTerminal(edges[j], null, source); - this.model.setGeometry(edges[j], geo); - } - } - } - } - - this.model.remove(cells[i]); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_REMOVED, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: splitEdge - * - * Splits the given edge by adding the newEdge between the previous source - * and the given cell and reconnecting the source of the given edge to the - * given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction - * is in progress. Returns the new edge that was inserted. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to be splitted. - * cells - <mxCells> that represents the cells to insert into the edge. - * newEdge - <mxCell> that represents the edge to be inserted. - * dx - Optional integer that specifies the vector to move the cells. - * dy - Optional integer that specifies the vector to move the cells. - */ -mxGraph.prototype.splitEdge = function(edge, cells, newEdge, dx, dy) -{ - dx = dx || 0; - dy = dy || 0; - - if (newEdge == null) - { - newEdge = this.cloneCells([edge])[0]; - } - - var parent = this.model.getParent(edge); - var source = this.model.getTerminal(edge, true); - - this.model.beginUpdate(); - try - { - this.cellsMoved(cells, dx, dy, false, false); - this.cellsAdded(cells, parent, this.model.getChildCount(parent), null, null, - true); - this.cellsAdded([newEdge], parent, this.model.getChildCount(parent), - source, cells[0], false); - this.cellConnected(edge, cells[0], true); - this.fireEvent(new mxEventObject(mxEvent.SPLIT_EDGE, 'edge', edge, - 'cells', cells, 'newEdge', newEdge, 'dx', dx, 'dy', dy)); - } - finally - { - this.model.endUpdate(); - } - - return newEdge; -}; - -/** - * Group: Cell visibility - */ - -/** - * Function: toggleCells - * - * Sets the visible state of the specified cells and all connected edges - * if includeEdges is true. The change is carried out using <cellsToggled>. - * This method fires <mxEvent.TOGGLE_CELLS> while the transaction is in - * progress. Returns the cells whose visible state was changed. - * - * Parameters: - * - * show - Boolean that specifies the visible state to be assigned. - * cells - Array of <mxCells> whose visible state should be changed. If - * null is specified then the selection cells are used. - * includeEdges - Optional boolean indicating if the visible state of all - * connected edges should be changed as well. Default is true. - */ -mxGraph.prototype.toggleCells = function(show, cells, includeEdges) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - // Adds all connected edges recursively - if (includeEdges) - { - cells = this.addAllEdges(cells); - } - - this.model.beginUpdate(); - try - { - this.cellsToggled(cells, show); - this.fireEvent(new mxEventObject(mxEvent.TOGGLE_CELLS, - 'show', show, 'cells', cells, 'includeEdges', includeEdges)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsToggled - * - * Sets the visible state of the specified cells. - * - * Parameters: - * - * cells - Array of <mxCells> whose visible state should be changed. - * show - Boolean that specifies the visible state to be assigned. - */ -mxGraph.prototype.cellsToggled = function(cells, show) -{ - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - this.model.setVisible(cells[i], show); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Folding - */ - -/** - * Function: foldCells - * - * Sets the collapsed state of the specified cells and all descendants - * if recurse is true. The change is carried out using <cellsFolded>. - * This method fires <mxEvent.FOLD_CELLS> while the transaction is in - * progress. Returns the cells whose collapsed state was changed. - * - * Parameters: - * - * collapsed - Boolean indicating the collapsed state to be assigned. - * recurse - Optional boolean indicating if the collapsed state of all - * descendants should be set. Default is false. - * cells - Array of <mxCells> whose collapsed state should be set. If - * null is specified then the foldable selection cells are used. - * checkFoldable - Optional boolean indicating of isCellFoldable should be - * checked. Default is false. - */ -mxGraph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable) -{ - recurse = (recurse != null) ? recurse : false; - - if (cells == null) - { - cells = this.getFoldableCells(this.getSelectionCells(), collapse); - } - - this.stopEditing(false); - - this.model.beginUpdate(); - try - { - this.cellsFolded(cells, collapse, recurse, checkFoldable); - this.fireEvent(new mxEventObject(mxEvent.FOLD_CELLS, - 'collapse', collapse, 'recurse', recurse, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsFolded - * - * Sets the collapsed state of the specified cells. This method fires - * <mxEvent.CELLS_FOLDED> while the transaction is in progress. Returns the - * cells whose collapsed state was changed. - * - * Parameters: - * - * cells - Array of <mxCells> whose collapsed state should be set. - * collapsed - Boolean indicating the collapsed state to be assigned. - * recurse - Boolean indicating if the collapsed state of all descendants - * should be set. - * checkFoldable - Optional boolean indicating of isCellFoldable should be - * checked. Default is false. - */ -mxGraph.prototype.cellsFolded = function(cells, collapse, recurse, checkFoldable) -{ - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if ((!checkFoldable || this.isCellFoldable(cells[i], collapse)) && - collapse != this.isCellCollapsed(cells[i])) - { - this.model.setCollapsed(cells[i], collapse); - this.swapBounds(cells[i], collapse); - - if (this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - - if (recurse) - { - var children = this.model.getChildren(cells[i]); - this.foldCells(children, collapse, recurse); - } - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_FOLDED, - 'cells', cells, 'collapse', collapse, 'recurse', recurse)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: swapBounds - * - * Swaps the alternate and the actual bounds in the geometry of the given - * cell invoking <updateAlternateBounds> before carrying out the swap. - * - * Parameters: - * - * cell - <mxCell> for which the bounds should be swapped. - * willCollapse - Boolean indicating if the cell is going to be collapsed. - */ -mxGraph.prototype.swapBounds = function(cell, willCollapse) -{ - if (cell != null) - { - var geo = this.model.getGeometry(cell); - - if (geo != null) - { - geo = geo.clone(); - - this.updateAlternateBounds(cell, geo, willCollapse); - geo.swap(); - - this.model.setGeometry(cell, geo); - } - } -}; - -/** - * Function: updateAlternateBounds - * - * Updates or sets the alternate bounds in the given geometry for the given - * cell depending on whether the cell is going to be collapsed. If no - * alternate bounds are defined in the geometry and - * <collapseToPreferredSize> is true, then the preferred size is used for - * the alternate bounds. The top, left corner is always kept at the same - * location. - * - * Parameters: - * - * cell - <mxCell> for which the geometry is being udpated. - * g - <mxGeometry> for which the alternate bounds should be updated. - * willCollapse - Boolean indicating if the cell is going to be collapsed. - */ -mxGraph.prototype.updateAlternateBounds = function(cell, geo, willCollapse) -{ - if (cell != null && geo != null) - { - if (geo.alternateBounds == null) - { - var bounds = geo; - - if (this.collapseToPreferredSize) - { - var tmp = this.getPreferredSizeForCell(cell); - - if (tmp != null) - { - bounds = tmp; - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - var startSize = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE); - - if (startSize > 0) - { - bounds.height = Math.max(bounds.height, startSize); - } - } - } - - geo.alternateBounds = new mxRectangle( - geo.x, geo.y, bounds.width, bounds.height); - } - else - { - geo.alternateBounds.x = geo.x; - geo.alternateBounds.y = geo.y; - } - } -}; - -/** - * Function: addAllEdges - * - * Returns an array with the given cells and all edges that are connected - * to a cell or one of its descendants. - */ -mxGraph.prototype.addAllEdges = function(cells) -{ - var allCells = cells.slice(); // FIXME: Required? - allCells = allCells.concat(this.getAllEdges(cells)); - - return allCells; -}; - -/** - * Function: getAllEdges - * - * Returns all edges connected to the given cells or its descendants. - */ -mxGraph.prototype.getAllEdges = function(cells) -{ - var edges = []; - - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - var edgeCount = this.model.getEdgeCount(cells[i]); - - for (var j = 0; j < edgeCount; j++) - { - edges.push(this.model.getEdgeAt(cells[i], j)); - } - - // Recurses - var children = this.model.getChildren(cells[i]); - edges = edges.concat(this.getAllEdges(children)); - } - } - - return edges; -}; - -/** - * Group: Cell sizing - */ - -/** - * Function: updateCellSize - * - * Updates the size of the given cell in the model using <cellSizeUpdated>. - * This method fires <mxEvent.UPDATE_CELL_SIZE> while the transaction is in - * progress. Returns the cell whose size was updated. - * - * Parameters: - * - * cell - <mxCell> whose size should be updated. - */ -mxGraph.prototype.updateCellSize = function(cell, ignoreChildren) -{ - ignoreChildren = (ignoreChildren != null) ? ignoreChildren : false; - - this.model.beginUpdate(); - try - { - this.cellSizeUpdated(cell, ignoreChildren); - this.fireEvent(new mxEventObject(mxEvent.UPDATE_CELL_SIZE, - 'cell', cell, 'ignoreChildren', ignoreChildren)); - } - finally - { - this.model.endUpdate(); - } - - return cell; -}; - -/** - * Function: cellSizeUpdated - * - * Updates the size of the given cell in the model using - * <getPreferredSizeForCell> to get the new size. - * - * Parameters: - * - * cell - <mxCell> for which the size should be changed. - */ -mxGraph.prototype.cellSizeUpdated = function(cell, ignoreChildren) -{ - if (cell != null) - { - this.model.beginUpdate(); - try - { - var size = this.getPreferredSizeForCell(cell); - var geo = this.model.getGeometry(cell); - - if (size != null && geo != null) - { - var collapsed = this.isCellCollapsed(cell); - geo = geo.clone(); - - if (this.isSwimlane(cell)) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - var cellStyle = this.model.getStyle(cell); - - if (cellStyle == null) - { - cellStyle = ''; - } - - if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - cellStyle = mxUtils.setStyle(cellStyle, - mxConstants.STYLE_STARTSIZE, size.height + 8); - - if (collapsed) - { - geo.height = size.height + 8; - } - - geo.width = size.width; - } - else - { - cellStyle = mxUtils.setStyle(cellStyle, - mxConstants.STYLE_STARTSIZE, size.width + 8); - - if (collapsed) - { - geo.width = size.width + 8; - } - - geo.height = size.height; - } - - this.model.setStyle(cell, cellStyle); - } - else - { - geo.width = size.width; - geo.height = size.height; - } - - if (!ignoreChildren && !collapsed) - { - var bounds = this.view.getBounds(this.model.getChildren(cell)); - - if (bounds != null) - { - var tr = this.view.translate; - var scale = this.view.scale; - - var width = (bounds.x + bounds.width) / scale - geo.x - tr.x; - var height = (bounds.y + bounds.height) / scale - geo.y - tr.y; - - geo.width = Math.max(geo.width, width); - geo.height = Math.max(geo.height, height); - } - } - - this.cellsResized([cell], [geo]); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: getPreferredSizeForCell - * - * Returns the preferred width and height of the given <mxCell> as an - * <mxRectangle>. - * - * Parameters: - * - * cell - <mxCell> for which the preferred size should be returned. - */ -mxGraph.prototype.getPreferredSizeForCell = function(cell) -{ - var result = null; - - if (cell != null) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (style != null && !this.model.isEdge(cell)) - { - var fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE; - var dx = 0; - var dy = 0; - - // Adds dimension of image if shape is a label - if (this.getImage(state) != null || style[mxConstants.STYLE_IMAGE] != null) - { - if (style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_LABEL) - { - if (style[mxConstants.STYLE_VERTICAL_ALIGN] == mxConstants.ALIGN_MIDDLE) - { - dx += parseFloat(style[mxConstants.STYLE_IMAGE_WIDTH]) || mxLabel.prototype.imageSize; - } - - if (style[mxConstants.STYLE_ALIGN] != mxConstants.ALIGN_CENTER) - { - dy += parseFloat(style[mxConstants.STYLE_IMAGE_HEIGHT]) || mxLabel.prototype.imageSize; - } - } - } - - // Adds spacings - dx += 2 * (style[mxConstants.STYLE_SPACING] || 0); - dx += style[mxConstants.STYLE_SPACING_LEFT] || 0; - dx += style[mxConstants.STYLE_SPACING_RIGHT] || 0; - - dy += 2 * (style[mxConstants.STYLE_SPACING] || 0); - dy += style[mxConstants.STYLE_SPACING_TOP] || 0; - dy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0; - - // Add spacing for collapse/expand icon - // LATER: Check alignment and use constants - // for image spacing - var image = this.getFoldingImage(state); - - if (image != null) - { - dx += image.width + 8; - } - - // Adds space for label - var value = this.getLabel(cell); - - if (value != null && value.length > 0) - { - if (!this.isHtmlLabel(cell)) - { - value = value.replace(/\n/g, '<br>'); - } - - var size = mxUtils.getSizeForString(value, - fontSize, style[mxConstants.STYLE_FONTFAMILY]); - var width = size.width + dx; - var height = size.height + dy; - - if (!mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - var tmp = height; - - height = width; - width = tmp; - } - - if (this.gridEnabled) - { - width = this.snap(width + this.gridSize / 2); - height = this.snap(height + this.gridSize / 2); - } - - result = new mxRectangle(0, 0, width, height); - } - else - { - var gs2 = 4 * this.gridSize; - result = new mxRectangle(0, 0, gs2, gs2); - } - } - } - - return result; -}; - -/** - * Function: handleGesture - * - * Invokes if a gesture event has been detected on a cell state. - * - * Parameters: - * - * state - <mxCellState> which was pinched. - * evt - Object that represents the gesture event. - */ -mxGraph.prototype.handleGesture = function(state, evt) -{ - if (Math.abs(1 - evt.scale) > 0.2) - { - var scale = this.view.scale; - var tr = this.view.translate; - - var w = state.width * evt.scale; - var h = state.height * evt.scale; - var x = state.x - (w - state.width) / 2; - var y = state.y - (h - state.height) / 2; - - var bounds = new mxRectangle(this.snap(x / scale) - tr.x, - this.snap(y / scale) - tr.y, - this.snap(w / scale), this.snap(h / scale)); - this.resizeCell(state.cell, bounds); - } -}; - -/** - * Function: resizeCell - * - * Sets the bounds of the given cell using <resizeCells>. Returns the - * cell which was passed to the function. - * - * Parameters: - * - * cell - <mxCell> whose bounds should be changed. - * bounds - <mxRectangle> that represents the new bounds. - */ -mxGraph.prototype.resizeCell = function(cell, bounds) -{ - return this.resizeCells([cell], [bounds])[0]; -}; - -/** - * Function: resizeCells - * - * Sets the bounds of the given cells and fires a <mxEvent.RESIZE_CELLS> - * event while the transaction is in progress. Returns the cells which - * have been passed to the function. - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be changed. - * bounds - Array of <mxRectangles> that represent the new bounds. - */ -mxGraph.prototype.resizeCells = function(cells, bounds) -{ - this.model.beginUpdate(); - try - { - this.cellsResized(cells, bounds); - this.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS, - 'cells', cells, 'bounds', bounds)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsResized - * - * Sets the bounds of the given cells and fires a <mxEvent.CELLS_RESIZED> - * event. If <extendParents> is true, then the parent is extended if a - * child size is changed so that it overlaps with the parent. - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be changed. - * bounds - Array of <mxRectangles> that represent the new bounds. - */ -mxGraph.prototype.cellsResized = function(cells, bounds) -{ - if (cells != null && bounds != null && cells.length == bounds.length) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var tmp = bounds[i]; - var geo = this.model.getGeometry(cells[i]); - - if (geo != null && (geo.x != tmp.x || geo.y != tmp.y || - geo.width != tmp.width || geo.height != tmp.height)) - { - geo = geo.clone(); - - if (geo.relative) - { - var offset = geo.offset; - - if (offset != null) - { - offset.x += tmp.x - geo.x; - offset.y += tmp.y - geo.y; - } - } - else - { - geo.x = tmp.x; - geo.y = tmp.y; - } - - geo.width = tmp.width; - geo.height = tmp.height; - - if (!geo.relative && this.model.isVertex(cells[i]) && - !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - this.model.setGeometry(cells[i], geo); - - if (this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - } - } - - if (this.resetEdgesOnResize) - { - this.resetEdges(cells); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_RESIZED, - 'cells', cells, 'bounds', bounds)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: extendParent - * - * Resizes the parents recursively so that they contain the complete area - * of the resized child cell. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxGraph.prototype.extendParent = function(cell) -{ - if (cell != null) - { - var parent = this.model.getParent(cell); - var p = this.model.getGeometry(parent); - - if (parent != null && p != null && !this.isCellCollapsed(parent)) - { - var geo = this.model.getGeometry(cell); - - if (geo != null && (p.width < geo.x + geo.width || - p.height < geo.y + geo.height)) - { - p = p.clone(); - - p.width = Math.max(p.width, geo.x + geo.width); - p.height = Math.max(p.height, geo.y + geo.height); - - this.cellsResized([parent], [p]); - } - } - } -}; - -/** - * Group: Cell moving - */ - -/** - * Function: importCells - * - * Clones and inserts the given cells into the graph using the move - * method and returns the inserted cells. This shortcut is used if - * cells are inserted via datatransfer. - */ -mxGraph.prototype.importCells = function(cells, dx, dy, target, evt) -{ - return this.moveCells(cells, dx, dy, true, target, evt); -}; - -/** - * Function: moveCells - * - * Moves or clones the specified cells and moves the cells or clones by the - * given amount, adding them to the optional target cell. The evt is the - * mouse event as the mouse was released. The change is carried out using - * <cellsMoved>. This method fires <mxEvent.MOVE_CELLS> while the - * transaction is in progress. Returns the cells that were moved. - * - * Use the following code to move all cells in the graph. - * - * (code) - * graph.moveCells(graph.getChildCells(null, true, true), 10, 10); - * (end) - * - * Parameters: - * - * cells - Array of <mxCells> to be moved, cloned or added to the target. - * dx - Integer that specifies the x-coordinate of the vector. Default is 0. - * dy - Integer that specifies the y-coordinate of the vector. Default is 0. - * clone - Boolean indicating if the cells should be cloned. Default is false. - * target - <mxCell> that represents the new parent of the cells. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt) -{ - dx = (dx != null) ? dx : 0; - dy = (dy != null) ? dy : 0; - clone = (clone != null) ? clone : false; - - if (cells != null && (dx != 0 || dy != 0 || clone || target != null)) - { - this.model.beginUpdate(); - try - { - if (clone) - { - cells = this.cloneCells(cells, this.isCloneInvalidEdges()); - - if (target == null) - { - target = this.getDefaultParent(); - } - } - - // FIXME: Cells should always be inserted first before any other edit - // to avoid forward references in sessions. - // Need to disable allowNegativeCoordinates if target not null to - // allow for temporary negative numbers until cellsAdded is called. - var previous = this.isAllowNegativeCoordinates(); - - if (target != null) - { - this.setAllowNegativeCoordinates(true); - } - - this.cellsMoved(cells, dx, dy, !clone && this.isDisconnectOnMove() - && this.isAllowDanglingEdges(), target == null); - - this.setAllowNegativeCoordinates(previous); - - if (target != null) - { - var index = this.model.getChildCount(target); - this.cellsAdded(cells, target, index, null, null, true); - } - - // Dispatches a move event - this.fireEvent(new mxEventObject(mxEvent.MOVE_CELLS, 'cells', cells, - 'dx', dx, 'dy', dy, 'clone', clone, 'target', target, 'event', evt)); - } - finally - { - this.model.endUpdate(); - } - } - - return cells; -}; - -/** - * Function: cellsMoved - * - * Moves the specified cells by the given vector, disconnecting the cells - * using disconnectGraph is disconnect is true. This method fires - * <mxEvent.CELLS_MOVED> while the transaction is in progress. - */ -mxGraph.prototype.cellsMoved = function(cells, dx, dy, disconnect, constrain) -{ - if (cells != null && (dx != 0 || dy != 0)) - { - this.model.beginUpdate(); - try - { - if (disconnect) - { - this.disconnectGraph(cells); - } - - for (var i = 0; i < cells.length; i++) - { - this.translateCell(cells[i], dx, dy); - - if (constrain) - { - this.constrainChild(cells[i]); - } - } - - if (this.resetEdgesOnMove) - { - this.resetEdges(cells); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_MOVED, - 'cells', cells, 'dx', dy, 'dy', dy, 'disconnect', disconnect)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: translateCell - * - * Translates the geometry of the given cell and stores the new, - * translated geometry in the model as an atomic change. - */ -mxGraph.prototype.translateCell = function(cell, dx, dy) -{ - var geo = this.model.getGeometry(cell); - - if (geo != null) - { - geo = geo.clone(); - geo.translate(dx, dy); - - if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - if (geo.relative && !this.model.isEdge(cell)) - { - if (geo.offset == null) - { - geo.offset = new mxPoint(dx, dy); - } - else - { - geo.offset.x += dx; - geo.offset.y += dy; - } - } - - this.model.setGeometry(cell, geo); - } -}; - -/** - * Function: getCellContainmentArea - * - * Returns the <mxRectangle> inside which a cell is to be kept. - * - * Parameters: - * - * cell - <mxCell> for which the area should be returned. - */ -mxGraph.prototype.getCellContainmentArea = function(cell) -{ - if (cell != null && !this.model.isEdge(cell)) - { - var parent = this.model.getParent(cell); - - if (parent == this.getDefaultParent() || parent == this.getCurrentRoot()) - { - return this.getMaximumGraphBounds(); - } - else if (parent != null && parent != this.getDefaultParent()) - { - var g = this.model.getGeometry(parent); - - if (g != null) - { - var x = 0; - var y = 0; - var w = g.width; - var h = g.height; - - if (this.isSwimlane(parent)) - { - var size = this.getStartSize(parent); - - x = size.width; - w -= size.width; - y = size.height; - h -= size.height; - } - - return new mxRectangle(x, y, w, h); - } - } - } - - return null; -}; - -/** - * Function: getMaximumGraphBounds - * - * Returns the bounds inside which the diagram should be kept as an - * <mxRectangle>. - */ -mxGraph.prototype.getMaximumGraphBounds = function() -{ - return this.maximumGraphBounds; -}; - -/** - * Function: constrainChild - * - * Keeps the given cell inside the bounds returned by - * <getCellContainmentArea> for its parent, according to the rules defined by - * <getOverlap> and <isConstrainChild>. This modifies the cell's geometry - * in-place and does not clone it. - * - * Parameters: - * - * cells - <mxCell> which should be constrained. - */ -mxGraph.prototype.constrainChild = function(cell) -{ - if (cell != null) - { - var geo = this.model.getGeometry(cell); - var area = (this.isConstrainChild(cell)) ? - this.getCellContainmentArea(cell) : - this.getMaximumGraphBounds(); - - if (geo != null && area != null) - { - // Keeps child within the content area of the parent - if (!geo.relative && (geo.x < area.x || geo.y < area.y || - area.width < geo.x + geo.width || area.height < geo.y + geo.height)) - { - var overlap = this.getOverlap(cell); - - if (area.width > 0) - { - geo.x = Math.min(geo.x, area.x + area.width - - (1 - overlap) * geo.width); - } - - if (area.height > 0) - { - geo.y = Math.min(geo.y, area.y + area.height - - (1 - overlap) * geo.height); - } - - geo.x = Math.max(geo.x, area.x - geo.width * overlap); - geo.y = Math.max(geo.y, area.y - geo.height * overlap); - } - } - } -}; - -/** - * Function: resetEdges - * - * Resets the control points of the edges that are connected to the given - * cells if not both ends of the edge are in the given cells array. - * - * Parameters: - * - * cells - Array of <mxCells> for which the connected edges should be - * reset. - */ -mxGraph.prototype.resetEdges = function(cells) -{ - if (cells != null) - { - // Prepares a hashtable for faster cell lookups - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var edges = this.model.getEdges(cells[i]); - - if (edges != null) - { - for (var j = 0; j < edges.length; j++) - { - var state = this.view.getState(edges[j]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[j], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[j], false); - - var sourceId = mxCellPath.create(source); - var targetId = mxCellPath.create(target); - - // Checks if one of the terminals is not in the given array - if (hash[sourceId] == null || hash[targetId] == null) - { - this.resetEdge(edges[j]); - } - } - } - - this.resetEdges(this.model.getChildren(cells[i])); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: resetEdge - * - * Resets the control points of the given edge. - * - * Parameters: - * - * edge - <mxCell> whose points should be reset. - */ -mxGraph.prototype.resetEdge = function(edge) -{ - var geo = this.model.getGeometry(edge); - - // Resets the control points - if (geo != null && geo.points != null && geo.points.length > 0) - { - geo = geo.clone(); - geo.points = []; - this.model.setGeometry(edge, geo); - } - - return edge; -}; - -/** - * Group: Cell connecting and connection constraints - */ - -/** - * Function: getAllConnectionConstraints - * - * Returns an array of all <mxConnectionConstraints> for the given terminal. If - * the shape of the given terminal is a <mxStencilShape> then the constraints - * of the corresponding <mxStencil> are returned. - * - * Parameters: - * - * terminal - <mxCellState> that represents the terminal. - * source - Boolean that specifies if the terminal is the source or target. - */ -mxGraph.prototype.getAllConnectionConstraints = function(terminal, source) -{ - if (terminal != null && terminal.shape != null && - terminal.shape instanceof mxStencilShape) - { - if (terminal.shape.stencil != null) - { - return terminal.shape.stencil.constraints; - } - } - - return null; -}; - -/** - * Function: getConnectionConstraint - * - * Returns an <mxConnectionConstraint> that describes the given connection - * point. This result can then be passed to <getConnectionPoint>. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - * terminal - <mxCellState> that represents the terminal. - * source - Boolean indicating if the terminal is the source or target. - */ -mxGraph.prototype.getConnectionConstraint = function(edge, terminal, source) -{ - var point = null; - var x = edge.style[(source) ? - mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X]; - - if (x != null) - { - var y = edge.style[(source) ? - mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y]; - - if (y != null) - { - point = new mxPoint(parseFloat(x), parseFloat(y)); - } - } - - var perimeter = false; - - if (point != null) - { - perimeter = mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, true); - } - - return new mxConnectionConstraint(point, perimeter); -}; - -/** - * Function: setConnectionConstraint - * - * Sets the <mxConnectionConstraint> that describes the given connection point. - * If no constraint is given then nothing is changed. To remove an existing - * constraint from the given edge, use an empty constraint instead. - * - * Parameters: - * - * edge - <mxCell> that represents the edge. - * terminal - <mxCell> that represents the terminal. - * source - Boolean indicating if the terminal is the source or target. - * constraint - Optional <mxConnectionConstraint> to be used for this - * connection. - */ -mxGraph.prototype.setConnectionConstraint = function(edge, terminal, source, constraint) -{ - if (constraint != null) - { - this.model.beginUpdate(); - try - { - if (constraint == null || constraint.point == null) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X, null, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y, null, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]); - } - else if (constraint.point != null) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X, constraint.point.x, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y, constraint.point.y, [edge]); - - // Only writes 0 since 1 is default - if (!constraint.perimeter) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, '0', [edge]); - } - else - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]); - } - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: getConnectionPoint - * - * Returns the nearest point in the list of absolute points or the center - * of the opposite terminal. - * - * Parameters: - * - * vertex - <mxCellState> that represents the vertex. - * constraint - <mxConnectionConstraint> that represents the connection point - * constraint as returned by <getConnectionConstraint>. - */ -mxGraph.prototype.getConnectionPoint = function(vertex, constraint) -{ - var point = null; - - if (vertex != null) - { - var bounds = this.view.getPerimeterBounds(vertex); - var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY()); - - var direction = vertex.style[mxConstants.STYLE_DIRECTION]; - var r1 = 0; - - // Bounds need to be rotated by 90 degrees for further computation - if (direction != null) - { - if (direction == 'north') - { - r1 += 270; - } - else if (direction == 'west') - { - r1 += 180; - } - else if (direction == 'south') - { - r1 += 90; - } - - // Bounds need to be rotated by 90 degrees for further computation - if (direction == 'north' || direction == 'south') - { - bounds.x += bounds.width / 2 - bounds.height / 2; - bounds.y += bounds.height / 2 - bounds.width / 2; - var tmp = bounds.width; - bounds.width = bounds.height; - bounds.height = tmp; - } - } - - if (constraint.point != null) - { - var sx = 1; - var sy = 1; - var dx = 0; - var dy = 0; - - // LATER: Add flipping support for image shapes - if (vertex.shape instanceof mxStencilShape) - { - var flipH = vertex.style[mxConstants.STYLE_STENCIL_FLIPH]; - var flipV = vertex.style[mxConstants.STYLE_STENCIL_FLIPV]; - - if (direction == 'north' || direction == 'south') - { - var tmp = flipH; - flipH = flipV; - flipV = tmp; - } - - if (flipH) - { - sx = -1; - dx = -bounds.width; - } - - if (flipV) - { - sy = -1; - dy = -bounds.height ; - } - } - - point = new mxPoint(bounds.x + constraint.point.x * bounds.width * sx - dx, - bounds.y + constraint.point.y * bounds.height * sy - dy); - } - - // Rotation for direction before projection on perimeter - var r2 = vertex.style[mxConstants.STYLE_ROTATION] || 0; - - if (constraint.perimeter) - { - if (r1 != 0 && point != null) - { - // Only 90 degrees steps possible here so no trig needed - var cos = 0; - var sin = 0; - - if (r1 == 90) - { - sin = 1; - } - else if (r1 == 180) - { - cos = -1; - } - else if (r2 == 270) - { - sin = -1; - } - - point = mxUtils.getRotatedPoint(point, cos, sin, cx); - } - - if (point != null && constraint.perimeter) - { - point = this.view.getPerimeterPoint(vertex, point, false); - } - } - else - { - r2 += r1; - } - - // Generic rotation after projection on perimeter - if (r2 != 0 && point != null) - { - var rad = mxUtils.toRadians(r2); - var cos = Math.cos(rad); - var sin = Math.sin(rad); - - point = mxUtils.getRotatedPoint(point, cos, sin, cx); - } - } - - return point; -}; - -/** - * Function: connectCell - * - * Connects the specified end of the given edge to the given terminal - * using <cellConnected> and fires <mxEvent.CONNECT_CELL> while the - * transaction is in progress. Returns the updated edge. - * - * Parameters: - * - * edge - <mxCell> whose terminal should be updated. - * terminal - <mxCell> that represents the new terminal to be used. - * source - Boolean indicating if the new terminal is the source or target. - * constraint - Optional <mxConnectionConstraint> to be used for this - * connection. - */ -mxGraph.prototype.connectCell = function(edge, terminal, source, constraint) -{ - this.model.beginUpdate(); - try - { - var previous = this.model.getTerminal(edge, source); - this.cellConnected(edge, terminal, source, constraint); - this.fireEvent(new mxEventObject(mxEvent.CONNECT_CELL, - 'edge', edge, 'terminal', terminal, 'source', source, - 'previous', previous)); - } - finally - { - this.model.endUpdate(); - } - - return edge; -}; - -/** - * Function: cellConnected - * - * Sets the new terminal for the given edge and resets the edge points if - * <resetEdgesOnConnect> is true. This method fires - * <mxEvent.CELL_CONNECTED> while the transaction is in progress. - * - * Parameters: - * - * edge - <mxCell> whose terminal should be updated. - * terminal - <mxCell> that represents the new terminal to be used. - * source - Boolean indicating if the new terminal is the source or target. - * constraint - <mxConnectionConstraint> to be used for this connection. - */ -mxGraph.prototype.cellConnected = function(edge, terminal, source, constraint) -{ - if (edge != null) - { - this.model.beginUpdate(); - try - { - var previous = this.model.getTerminal(edge, source); - - // Updates the constraint - this.setConnectionConstraint(edge, terminal, source, constraint); - - // Checks if the new terminal is a port, uses the ID of the port in the - // style and the parent of the port as the actual terminal of the edge. - if (this.isPortsEnabled()) - { - var id = null; - - if (this.isPort(terminal)) - { - id = terminal.getId(); - terminal = this.getTerminalForPort(terminal, source); - } - - // Sets or resets all previous information for connecting to a child port - var key = (source) ? mxConstants.STYLE_SOURCE_PORT : - mxConstants.STYLE_TARGET_PORT; - this.setCellStyles(key, id, [edge]); - } - - this.model.setTerminal(edge, terminal, source); - - if (this.resetEdgesOnConnect) - { - this.resetEdge(edge); - } - - this.fireEvent(new mxEventObject(mxEvent.CELL_CONNECTED, - 'edge', edge, 'terminal', terminal, 'source', source, - 'previous', previous)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: disconnectGraph - * - * Disconnects the given edges from the terminals which are not in the - * given array. - * - * Parameters: - * - * cells - Array of <mxCells> to be disconnected. - */ -mxGraph.prototype.disconnectGraph = function(cells) -{ - if (cells != null) - { - this.model.beginUpdate(); - try - { - var scale = this.view.scale; - var tr = this.view.translate; - - // Prepares a hashtable for faster cell lookups - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - for (var i = 0; i < cells.length; i++) - { - if (this.model.isEdge(cells[i])) - { - var geo = this.model.getGeometry(cells[i]); - - if (geo != null) - { - var state = this.view.getState(cells[i]); - var pstate = this.view.getState( - this.model.getParent(cells[i])); - - if (state != null && - pstate != null) - { - geo = geo.clone(); - - var dx = -pstate.origin.x; - var dy = -pstate.origin.y; - var pts = state.absolutePoints; - - var src = this.model.getTerminal(cells[i], true); - - if (src != null && this.isCellDisconnectable(cells[i], src, true)) - { - var srcId = mxCellPath.create(src); - - while (src != null && hash[srcId] == null) - { - src = this.model.getParent(src); - srcId = mxCellPath.create(src); - } - - if (src == null) - { - geo.setTerminalPoint( - new mxPoint(pts[0].x / scale - tr.x + dx, - pts[0].y / scale - tr.y + dy), true); - this.model.setTerminal(cells[i], null, true); - } - } - - var trg = this.model.getTerminal(cells[i], false); - - if (trg != null && this.isCellDisconnectable(cells[i], trg, false)) - { - var trgId = mxCellPath.create(trg); - - while (trg != null && hash[trgId] == null) - { - trg = this.model.getParent(trg); - trgId = mxCellPath.create(trg); - } - - if (trg == null) - { - var n = pts.length - 1; - geo.setTerminalPoint( - new mxPoint(pts[n].x / scale - tr.x + dx, - pts[n].y / scale - tr.y + dy), false); - this.model.setTerminal(cells[i], null, false); - } - } - - this.model.setGeometry(cells[i], geo); - } - } - } - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Drilldown - */ - -/** - * Function: getCurrentRoot - * - * Returns the current root of the displayed cell hierarchy. This is a - * shortcut to <mxGraphView.currentRoot> in <view>. - */ - mxGraph.prototype.getCurrentRoot = function() - { - return this.view.currentRoot; - }; - - /** - * Function: getTranslateForRoot - * - * Returns the translation to be used if the given cell is the root cell as - * an <mxPoint>. This implementation returns null. - * - * Example: - * - * To keep the children at their absolute position while stepping into groups, - * this function can be overridden as follows. - * - * (code) - * var offset = new mxPoint(0, 0); - * - * while (cell != null) - * { - * var geo = this.model.getGeometry(cell); - * - * if (geo != null) - * { - * offset.x -= geo.x; - * offset.y -= geo.y; - * } - * - * cell = this.model.getParent(cell); - * } - * - * return offset; - * (end) - * - * Parameters: - * - * cell - <mxCell> that represents the root. - */ -mxGraph.prototype.getTranslateForRoot = function(cell) -{ - return null; -}; - -/** - * Function: isPort - * - * Returns true if the given cell is a "port", that is, when connecting to - * it, the cell returned by getTerminalForPort should be used as the - * terminal and the port should be referenced by the ID in either the - * mxConstants.STYLE_SOURCE_PORT or the or the - * mxConstants.STYLE_TARGET_PORT. Note that a port should not be movable. - * This implementation always returns false. - * - * A typical implementation is the following: - * - * (code) - * graph.isPort = function(cell) - * { - * var geo = this.getCellGeometry(cell); - * - * return (geo != null) ? geo.relative : false; - * }; - * (end) - * - * Parameters: - * - * cell - <mxCell> that represents the port. - */ -mxGraph.prototype.isPort = function(cell) -{ - return false; -}; - -/** - * Function: getTerminalForPort - * - * Returns the terminal to be used for a given port. This implementation - * always returns the parent cell. - * - * Parameters: - * - * cell - <mxCell> that represents the port. - * source - If the cell is the source or target port. - */ -mxGraph.prototype.getTerminalForPort = function(cell, source) -{ - return this.model.getParent(cell); -}; - -/** - * Function: getChildOffsetForCell - * - * Returns the offset to be used for the cells inside the given cell. The - * root and layer cells may be identified using <mxGraphModel.isRoot> and - * <mxGraphModel.isLayer>. For all other current roots, the - * <mxGraphView.currentRoot> field points to the respective cell, so that - * the following holds: cell == this.view.currentRoot. This implementation - * returns null. - * - * Parameters: - * - * cell - <mxCell> whose offset should be returned. - */ -mxGraph.prototype.getChildOffsetForCell = function(cell) -{ - return null; -}; - -/** - * Function: enterGroup - * - * Uses the given cell as the root of the displayed cell hierarchy. If no - * cell is specified then the selection cell is used. The cell is only used - * if <isValidRoot> returns true. - * - * Parameters: - * - * cell - Optional <mxCell> to be used as the new root. Default is the - * selection cell. - */ -mxGraph.prototype.enterGroup = function(cell) -{ - cell = cell || this.getSelectionCell(); - - if (cell != null && this.isValidRoot(cell)) - { - this.view.setCurrentRoot(cell); - this.clearSelection(); - } -}; - -/** - * Function: exitGroup - * - * Changes the current root to the next valid root in the displayed cell - * hierarchy. - */ -mxGraph.prototype.exitGroup = function() -{ - var root = this.model.getRoot(); - var current = this.getCurrentRoot(); - - if (current != null) - { - var next = this.model.getParent(current); - - // Finds the next valid root in the hierarchy - while (next != root && !this.isValidRoot(next) && - this.model.getParent(next) != root) - { - next = this.model.getParent(next); - } - - // Clears the current root if the new root is - // the model's root or one of the layers. - if (next == root || this.model.getParent(next) == root) - { - this.view.setCurrentRoot(null); - } - else - { - this.view.setCurrentRoot(next); - } - - var state = this.view.getState(current); - - // Selects the previous root in the graph - if (state != null) - { - this.setSelectionCell(current); - } - } -}; - -/** - * Function: home - * - * Uses the root of the model as the root of the displayed cell hierarchy - * and selects the previous root. - */ -mxGraph.prototype.home = function() -{ - var current = this.getCurrentRoot(); - - if (current != null) - { - this.view.setCurrentRoot(null); - var state = this.view.getState(current); - - if (state != null) - { - this.setSelectionCell(current); - } - } -}; - -/** - * Function: isValidRoot - * - * Returns true if the given cell is a valid root for the cell display - * hierarchy. This implementation returns true for all non-null values. - * - * Parameters: - * - * cell - <mxCell> which should be checked as a possible root. - */ -mxGraph.prototype.isValidRoot = function(cell) -{ - return (cell != null); -}; - -/** - * Group: Graph display - */ - -/** - * Function: getGraphBounds - * - * Returns the bounds of the visible graph. Shortcut to - * <mxGraphView.getGraphBounds>. See also: <getBoundingBoxFromGeometry>. - */ - mxGraph.prototype.getGraphBounds = function() - { - return this.view.getGraphBounds(); - }; - -/** - * Function: getCellBounds - * - * Returns the scaled, translated bounds for the given cell. See - * <mxGraphView.getBounds> for arrays. - * - * Parameters: - * - * cell - <mxCell> whose bounds should be returned. - * includeEdge - Optional boolean that specifies if the bounds of - * the connected edges should be included. Default is false. - * includeDescendants - Optional boolean that specifies if the bounds - * of all descendants should be included. Default is false. - */ -mxGraph.prototype.getCellBounds = function(cell, includeEdges, includeDescendants) -{ - var cells = [cell]; - - // Includes all connected edges - if (includeEdges) - { - cells = cells.concat(this.model.getEdges(cell)); - } - - var result = this.view.getBounds(cells); - - // Recursively includes the bounds of the children - if (includeDescendants) - { - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var tmp = this.getCellBounds(this.model.getChildAt(cell, i), - includeEdges, true); - - if (result != null) - { - result.add(tmp); - } - else - { - result = tmp; - } - } - } - - return result; -}; - -/** - * Function: getBoundingBoxFromGeometry - * - * Returns the bounding box for the geometries of the vertices in the - * given array of cells. This can be used to find the graph bounds during - * a layout operation (ie. before the last endUpdate) as follows: - * - * (code) - * var cells = graph.getChildCells(graph.getDefaultParent(), true, true); - * var bounds = graph.getBoundingBoxFromGeometry(cells, true); - * (end) - * - * This can then be used to move cells to the origin: - * - * (code) - * if (bounds.x < 0 || bounds.y < 0) - * { - * graph.moveCells(cells, -Math.min(bounds.x, 0), -Math.min(bounds.y, 0)) - * } - * (end) - * - * Or to translate the graph view: - * - * (code) - * if (bounds.x < 0 || bounds.y < 0) - * { - * graph.view.setTranslate(-Math.min(bounds.x, 0), -Math.min(bounds.y, 0)); - * } - * (end) - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be returned. - * includeEdges - Specifies if edge bounds should be included by computing - * the bounding box for all points its geometry. Default is false. - */ -mxGraph.prototype.getBoundingBoxFromGeometry = function(cells, includeEdges) -{ - includeEdges = (includeEdges != null) ? includeEdges : false; - var result = null; - - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - if (includeEdges || this.model.isVertex(cells[i])) - { - // Computes the bounding box for the points in the geometry - var geo = this.getCellGeometry(cells[i]); - - if (geo != null) - { - var pts = geo.points; - - if (pts != null && pts.length > 0) - { - var tmp = new mxRectangle(pts[0].x, pts[0].y, 0, 0); - var addPoint = function(pt) - { - if (pt != null) - { - tmp.add(new mxRectangle(pt.x, pt.y, 0, 0)); - } - }; - - for (var j = 1; j < pts.length; j++) - { - addPoint(pts[j]); - } - - addPoint(geo.getTerminalPoint(true)); - addPoint(geo.getTerminalPoint(false)); - } - - if (result == null) - { - result = new mxRectangle(geo.x, geo.y, geo.width, geo.height); - } - else - { - result.add(geo); - } - } - } - } - } - - return result; -}; - -/** - * Function: refresh - * - * Clears all cell states or the states for the hierarchy starting at the - * given cell and validates the graph. This fires a refresh event as the - * last step. - * - * Parameters: - * - * cell - Optional <mxCell> for which the cell states should be cleared. - */ -mxGraph.prototype.refresh = function(cell) -{ - this.view.clear(cell, cell == null); - this.view.validate(); - this.sizeDidChange(); - this.fireEvent(new mxEventObject(mxEvent.REFRESH)); -}; - -/** - * Function: snap - * - * Snaps the given numeric value to the grid if <gridEnabled> is true. - * - * Parameters: - * - * value - Numeric value to be snapped to the grid. - */ -mxGraph.prototype.snap = function(value) -{ - if (this.gridEnabled) - { - value = Math.round(value / this.gridSize ) * this.gridSize; - } - - return value; -}; - -/** - * Function: panGraph - * - * Shifts the graph display by the given amount. This is used to preview - * panning operations, use <mxGraphView.setTranslate> to set a persistent - * translation of the view. Fires <mxEvent.PAN>. - * - * Parameters: - * - * dx - Amount to shift the graph along the x-axis. - * dy - Amount to shift the graph along the y-axis. - */ -mxGraph.prototype.panGraph = function(dx, dy) -{ - if (this.useScrollbarsForPanning && mxUtils.hasScrollbars(this.container)) - { - this.container.scrollLeft = -dx; - this.container.scrollTop = -dy; - } - else - { - var canvas = this.view.getCanvas(); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - // Puts everything inside the container in a DIV so that it - // can be moved without changing the state of the container - if (dx == 0 && dy == 0) - { - // Workaround for ignored removeAttribute on SVG element in IE9 standards - if (mxClient.IS_IE) - { - canvas.setAttribute('transform', 'translate('+ dx + ',' + dy + ')'); - } - else - { - canvas.removeAttribute('transform'); - } - - if (this.shiftPreview1 != null) - { - var child = this.shiftPreview1.firstChild; - - while (child != null) - { - var next = child.nextSibling; - this.container.appendChild(child); - child = next; - } - - this.shiftPreview1.parentNode.removeChild(this.shiftPreview1); - this.shiftPreview1 = null; - - this.container.appendChild(canvas.parentNode); - - child = this.shiftPreview2.firstChild; - - while (child != null) - { - var next = child.nextSibling; - this.container.appendChild(child); - child = next; - } - - this.shiftPreview2.parentNode.removeChild(this.shiftPreview2); - this.shiftPreview2 = null; - } - } - else - { - canvas.setAttribute('transform', 'translate('+ dx + ',' + dy + ')'); - - if (this.shiftPreview1 == null) - { - // Needs two divs for stuff before and after the SVG element - this.shiftPreview1 = document.createElement('div'); - this.shiftPreview1.style.position = 'absolute'; - this.shiftPreview1.style.overflow = 'visible'; - - this.shiftPreview2 = document.createElement('div'); - this.shiftPreview2.style.position = 'absolute'; - this.shiftPreview2.style.overflow = 'visible'; - - var current = this.shiftPreview1; - var child = this.container.firstChild; - - while (child != null) - { - var next = child.nextSibling; - - // SVG element is moved via transform attribute - if (child != canvas.parentNode) - { - current.appendChild(child); - } - else - { - current = this.shiftPreview2; - } - - child = next; - } - - this.container.insertBefore(this.shiftPreview1, canvas.parentNode); - this.container.appendChild(this.shiftPreview2); - } - - this.shiftPreview1.style.left = dx + 'px'; - this.shiftPreview1.style.top = dy + 'px'; - this.shiftPreview2.style.left = dx + 'px'; - this.shiftPreview2.style.top = dy + 'px'; - } - } - else - { - canvas.style.left = dx + 'px'; - canvas.style.top = dy + 'px'; - } - - this.panDx = dx; - this.panDy = dy; - - this.fireEvent(new mxEventObject(mxEvent.PAN)); - } -}; - -/** - * Function: zoomIn - * - * Zooms into the graph by <zoomFactor>. - */ -mxGraph.prototype.zoomIn = function() -{ - this.zoom(this.zoomFactor); -}; - -/** - * Function: zoomOut - * - * Zooms out of the graph by <zoomFactor>. - */ -mxGraph.prototype.zoomOut = function() -{ - this.zoom(1 / this.zoomFactor); -}; - -/** - * Function: zoomActual - * - * Resets the zoom and panning in the view. - */ -mxGraph.prototype.zoomActual = function() -{ - if (this.view.scale == 1) - { - this.view.setTranslate(0, 0); - } - else - { - this.view.translate.x = 0; - this.view.translate.y = 0; - - this.view.setScale(1); - } -}; - -/** - * Function: zoomTo - * - * Zooms the graph to the given scale with an optional boolean center - * argument, which is passd to <zoom>. - */ -mxGraph.prototype.zoomTo = function(scale, center) -{ - this.zoom(scale / this.view.scale, center); -}; - -/** - * Function: zoom - * - * Zooms the graph using the given factor. Center is an optional boolean - * argument that keeps the graph scrolled to the center. If the center argument - * is omitted, then <centerZoom> will be used as its value. - */ -mxGraph.prototype.zoom = function(factor, center) -{ - center = (center != null) ? center : this.centerZoom; - var scale = this.view.scale * factor; - var state = this.view.getState(this.getSelectionCell()); - - if (this.keepSelectionVisibleOnZoom && state != null) - { - var rect = new mxRectangle( - state.x * factor, - state.y * factor, - state.width * factor, - state.height * factor); - - // Refreshes the display only once if a - // scroll is carried out - this.view.scale = scale; - - if (!this.scrollRectToVisible(rect)) - { - this.view.revalidate(); - - // Forces an event to be fired but does not revalidate again - this.view.setScale(scale); - } - } - else if (center && !mxUtils.hasScrollbars(this.container)) - { - var dx = this.container.offsetWidth; - var dy = this.container.offsetHeight; - - if (factor > 1) - { - var f = (factor -1) / (scale * 2); - dx *= -f; - dy *= -f; - } - else - { - var f = (1/factor -1) / (this.view.scale * 2); - dx *= f; - dy *= f; - } - - this.view.scaleAndTranslate(scale, - this.view.translate.x + dx, - this.view.translate.y + dy); - } - else - { - this.view.setScale(scale); - - if (mxUtils.hasScrollbars(this.container)) - { - var dx = 0; - var dy = 0; - - if (center) - { - dx = this.container.offsetWidth * (factor - 1) / 2; - dy = this.container.offsetHeight * (factor - 1) / 2; - } - - this.container.scrollLeft = Math.round(this.container.scrollLeft * factor + dx); - this.container.scrollTop = Math.round(this.container.scrollTop * factor + dy); - } - } -}; - -/** - * Function: zoomToRect - * - * Zooms the graph to the specified rectangle. If the rectangle does not have same aspect - * ratio as the display container, it is increased in the smaller relative dimension only - * until the aspect match. The original rectangle is centralised within this expanded one. - * - * Note that the input rectangular must be un-scaled and un-translated. - * - * Parameters: - * - * rect - The un-scaled and un-translated rectangluar region that should be just visible - * after the operation - */ -mxGraph.prototype.zoomToRect = function(rect) -{ - var scaleX = this.container.clientWidth / rect.width; - var scaleY = this.container.clientHeight / rect.height; - var aspectFactor = scaleX / scaleY; - - // Remove any overlap of the rect outside the client area - rect.x = Math.max(0, rect.x); - rect.y = Math.max(0, rect.y); - var rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width); - var rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height); - rect.width = rectRight - rect.x; - rect.height = rectBottom - rect.y; - - // The selection area has to be increased to the same aspect - // ratio as the container, centred around the centre point of the - // original rect passed in. - if (aspectFactor < 1.0) - { - // Height needs increasing - var newHeight = rect.height / aspectFactor; - var deltaHeightBuffer = (newHeight - rect.height) / 2.0; - rect.height = newHeight; - - // Assign up to half the buffer to the upper part of the rect, not crossing 0 - // put the rest on the bottom - var upperBuffer = Math.min(rect.y , deltaHeightBuffer); - rect.y = rect.y - upperBuffer; - - // Check if the bottom has extended too far - rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height); - rect.height = rectBottom - rect.y; - } - else - { - // Width needs increasing - var newWidth = rect.width * aspectFactor; - var deltaWidthBuffer = (newWidth - rect.width) / 2.0; - rect.width = newWidth; - - // Assign up to half the buffer to the upper part of the rect, not crossing 0 - // put the rest on the bottom - var leftBuffer = Math.min(rect.x , deltaWidthBuffer); - rect.x = rect.x - leftBuffer; - - // Check if the right hand side has extended too far - rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width); - rect.width = rectRight - rect.x; - } - - var scale = this.container.clientWidth / rect.width; - - if (!mxUtils.hasScrollbars(this.container)) - { - this.view.scaleAndTranslate(scale, -rect.x, -rect.y); - } - else - { - this.view.setScale(scale); - this.container.scrollLeft = Math.round(rect.x * scale); - this.container.scrollTop = Math.round(rect.y * scale); - } -}; - -/** - * Function: fit - * - * Scales the graph such that the complete diagram fits into <container> and - * returns the current scale in the view. To fit an initial graph prior to - * rendering, set <mxGraphView.rendering> to false prior to changing the model - * and execute the following after changing the model. - * - * (code) - * graph.fit(); - * graph.view.rendering = true; - * graph.refresh(); - * (end) - * - * Parameters: - * - * border - Optional number that specifies the border. Default is 0. - * keepOrigin - Optional boolean that specifies if the translate should be - * changed. Default is false. - */ -mxGraph.prototype.fit = function(border, keepOrigin) -{ - if (this.container != null) - { - border = (border != null) ? border : 0; - keepOrigin = (keepOrigin != null) ? keepOrigin : false; - - var w1 = this.container.clientWidth; - var h1 = this.container.clientHeight; - - var bounds = this.view.getGraphBounds(); - - if (keepOrigin && bounds.x != null && bounds.y != null) - { - bounds.width += bounds.x; - bounds.height += bounds.y; - bounds.x = 0; - bounds.y = 0; - } - - var s = this.view.scale; - var w2 = bounds.width / s; - var h2 = bounds.height / s; - - // Fits to the size of the background image if required - if (this.backgroundImage != null) - { - w2 = Math.max(w2, this.backgroundImage.width - bounds.x / s); - h2 = Math.max(h2, this.backgroundImage.height - bounds.y / s); - } - - var b = (keepOrigin) ? border : 2 * border; - var s2 = Math.floor(Math.min(w1 / (w2 + b), h1 / (h2 + b)) * 100) / 100; - - if (this.minFitScale != null) - { - s2 = Math.max(s2, this.minFitScale); - } - - if (this.maxFitScale != null) - { - s2 = Math.min(s2, this.maxFitScale); - } - - if (!keepOrigin) - { - if (!mxUtils.hasScrollbars(this.container)) - { - var x0 = (bounds.x != null) ? Math.floor(this.view.translate.x - bounds.x / s + border + 1) : border; - var y0 = (bounds.y != null) ? Math.floor(this.view.translate.y - bounds.y / s + border + 1) : border; - - this.view.scaleAndTranslate(s2, x0, y0); - } - else - { - this.view.setScale(s2); - - if (bounds.x != null) - { - this.container.scrollLeft = Math.round(bounds.x / s) * s2 - border - - Math.max(0, (this.container.clientWidth - w2 * s2) / 2); - } - - if (bounds.y != null) - { - this.container.scrollTop = Math.round(bounds.y / s) * s2 - border - - Math.max(0, (this.container.clientHeight - h2 * s2) / 2); - } - } - } - else if (this.view.scale != s2) - { - this.view.setScale(s2); - } - } - - return this.view.scale; -}; - -/** - * Function: scrollCellToVisible - * - * Pans the graph so that it shows the given cell. Optionally the cell may - * be centered in the container. - * - * To center a given graph if the <container> has no scrollbars, use the following code. - * - * [code] - * var bounds = graph.getGraphBounds(); - * graph.view.setTranslate(-bounds.x - (bounds.width - container.clientWidth) / 2, - * -bounds.y - (bounds.height - container.clientHeight) / 2); - * [/code] - * - * Parameters: - * - * cell - <mxCell> to be made visible. - * center - Optional boolean flag. Default is false. - */ -mxGraph.prototype.scrollCellToVisible = function(cell, center) -{ - var x = -this.view.translate.x; - var y = -this.view.translate.y; - - var state = this.view.getState(cell); - - if (state != null) - { - var bounds = new mxRectangle(x + state.x, y + state.y, state.width, - state.height); - - if (center && this.container != null) - { - var w = this.container.clientWidth; - var h = this.container.clientHeight; - - bounds.x = bounds.getCenterX() - w / 2; - bounds.width = w; - bounds.y = bounds.getCenterY() - h / 2; - bounds.height = h; - } - - if (this.scrollRectToVisible(bounds)) - { - // Triggers an update via the view's event source - this.view.setTranslate(this.view.translate.x, this.view.translate.y); - } - } -}; - -/** - * Function: scrollRectToVisible - * - * Pans the graph so that it shows the given rectangle. - * - * Parameters: - * - * rect - <mxRectangle> to be made visible. - */ -mxGraph.prototype.scrollRectToVisible = function(rect) -{ - var isChanged = false; - - if (rect != null) - { - var w = this.container.offsetWidth; - var h = this.container.offsetHeight; - - var widthLimit = Math.min(w, rect.width); - var heightLimit = Math.min(h, rect.height); - - if (mxUtils.hasScrollbars(this.container)) - { - var c = this.container; - rect.x += this.view.translate.x; - rect.y += this.view.translate.y; - var dx = c.scrollLeft - rect.x; - var ddx = Math.max(dx - c.scrollLeft, 0); - - if (dx > 0) - { - c.scrollLeft -= dx + 2; - } - else - { - dx = rect.x + widthLimit - c.scrollLeft - c.clientWidth; - - if (dx > 0) - { - c.scrollLeft += dx + 2; - } - } - - var dy = c.scrollTop - rect.y; - var ddy = Math.max(0, dy - c.scrollTop); - - if (dy > 0) - { - c.scrollTop -= dy + 2; - } - else - { - dy = rect.y + heightLimit - c.scrollTop - c.clientHeight; - - if (dy > 0) - { - c.scrollTop += dy + 2; - } - } - - if (!this.useScrollbarsForPanning && (ddx != 0 || ddy != 0)) - { - this.view.setTranslate(ddx, ddy); - } - } - else - { - var x = -this.view.translate.x; - var y = -this.view.translate.y; - - var s = this.view.scale; - - if (rect.x + widthLimit > x + w) - { - this.view.translate.x -= (rect.x + widthLimit - w - x) / s; - isChanged = true; - } - - if (rect.y + heightLimit > y + h) - { - this.view.translate.y -= (rect.y + heightLimit - h - y) / s; - isChanged = true; - } - - if (rect.x < x) - { - this.view.translate.x += (x - rect.x) / s; - isChanged = true; - } - - if (rect.y < y) - { - this.view.translate.y += (y - rect.y) / s; - isChanged = true; - } - - if (isChanged) - { - this.view.refresh(); - - // Repaints selection marker (ticket 18) - if (this.selectionCellsHandler != null) - { - this.selectionCellsHandler.refresh(); - } - } - } - } - - return isChanged; -}; - -/** - * Function: getCellGeometry - * - * Returns the <mxGeometry> for the given cell. This implementation uses - * <mxGraphModel.getGeometry>. Subclasses can override this to implement - * specific geometries for cells in only one graph, that is, it can return - * geometries that depend on the current state of the view. - * - * Parameters: - * - * cell - <mxCell> whose geometry should be returned. - */ -mxGraph.prototype.getCellGeometry = function(cell) -{ - return this.model.getGeometry(cell); -}; - -/** - * Function: isCellVisible - * - * Returns true if the given cell is visible in this graph. This - * implementation uses <mxGraphModel.isVisible>. Subclassers can override - * this to implement specific visibility for cells in only one graph, that - * is, without affecting the visible state of the cell. - * - * When using dynamic filter expressions for cell visibility, then the - * graph should be revalidated after the filter expression has changed. - * - * Parameters: - * - * cell - <mxCell> whose visible state should be returned. - */ -mxGraph.prototype.isCellVisible = function(cell) -{ - return this.model.isVisible(cell); -}; - -/** - * Function: isCellCollapsed - * - * Returns true if the given cell is collapsed in this graph. This - * implementation uses <mxGraphModel.isCollapsed>. Subclassers can override - * this to implement specific collapsed states for cells in only one graph, - * that is, without affecting the collapsed state of the cell. - * - * When using dynamic filter expressions for the collapsed state, then the - * graph should be revalidated after the filter expression has changed. - * - * Parameters: - * - * cell - <mxCell> whose collapsed state should be returned. - */ -mxGraph.prototype.isCellCollapsed = function(cell) -{ - return this.model.isCollapsed(cell); -}; - -/** - * Function: isCellConnectable - * - * Returns true if the given cell is connectable in this graph. This - * implementation uses <mxGraphModel.isConnectable>. Subclassers can override - * this to implement specific connectable states for cells in only one graph, - * that is, without affecting the connectable state of the cell in the model. - * - * Parameters: - * - * cell - <mxCell> whose connectable state should be returned. - */ -mxGraph.prototype.isCellConnectable = function(cell) -{ - return this.model.isConnectable(cell); -}; - -/** - * Function: isOrthogonal - * - * Returns true if perimeter points should be computed such that the - * resulting edge has only horizontal or vertical segments. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - */ -mxGraph.prototype.isOrthogonal = function(edge) -{ - var orthogonal = edge.style[mxConstants.STYLE_ORTHOGONAL]; - - if (orthogonal != null) - { - return orthogonal; - } - - var tmp = this.view.getEdgeStyle(edge); - - return tmp == mxEdgeStyle.SegmentConnector || - tmp == mxEdgeStyle.ElbowConnector || - tmp == mxEdgeStyle.SideToSide || - tmp == mxEdgeStyle.TopToBottom || - tmp == mxEdgeStyle.EntityRelation || - tmp == mxEdgeStyle.OrthConnector; -}; - -/** - * Function: isLoop - * - * Returns true if the given cell state is a loop. - * - * Parameters: - * - * state - <mxCellState> that represents a potential loop. - */ -mxGraph.prototype.isLoop = function(state) -{ - var src = state.getVisibleTerminalState(true); - var trg = state.getVisibleTerminalState(false); - - return (src != null && src == trg); -}; - -/** - * Function: isCloneEvent - * - * Returns true if the given event is a clone event. This implementation - * returns true if control is pressed. - */ -mxGraph.prototype.isCloneEvent = function(evt) -{ - return mxEvent.isControlDown(evt); -}; - -/** - * Function: isToggleEvent - * - * Returns true if the given event is a toggle event. This implementation - * returns true if the meta key (Cmd) is pressed on Macs or if control is - * pressed on any other platform. - */ -mxGraph.prototype.isToggleEvent = function(evt) -{ - return (mxClient.IS_MAC) ? mxEvent.isMetaDown(evt) : mxEvent.isControlDown(evt); -}; - -/** - * Function: isGridEnabledEvent - * - * Returns true if the given mouse event should be aligned to the grid. - */ -mxGraph.prototype.isGridEnabledEvent = function(evt) -{ - return evt != null && !mxEvent.isAltDown(evt); -}; - -/** - * Function: isConstrainedEvent - * - * Returns true if the given mouse event should be aligned to the grid. - */ -mxGraph.prototype.isConstrainedEvent = function(evt) -{ - return mxEvent.isShiftDown(evt); -}; - -/** - * Function: isForceMarqueeEvent - * - * Returns true if the given event forces marquee selection. This implementation - * returns true if alt is pressed. - */ -mxGraph.prototype.isForceMarqueeEvent = function(evt) -{ - return mxEvent.isAltDown(evt); -}; - -/** - * Group: Validation - */ - -/** - * Function: validationAlert - * - * Displays the given validation error in a dialog. This implementation uses - * mxUtils.alert. - */ -mxGraph.prototype.validationAlert = function(message) -{ - mxUtils.alert(message); -}; - -/** - * Function: isEdgeValid - * - * Checks if the return value of <getEdgeValidationError> for the given - * arguments is null. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.isEdgeValid = function(edge, source, target) -{ - return this.getEdgeValidationError(edge, source, target) == null; -}; - -/** - * Function: getEdgeValidationError - * - * Returns the validation error message to be displayed when inserting or - * changing an edges' connectivity. A return value of null means the edge - * is valid, a return value of '' means it's not valid, but do not display - * an error message. Any other (non-empty) string returned from this method - * is displayed as an error message when trying to connect an edge to a - * source and target. This implementation uses the <multiplicities>, and - * checks <multigraph>, <allowDanglingEdges> and <allowLoops> to generate - * validation errors. - * - * For extending this method with specific checks for source/target cells, - * the method can be extended as follows. Returning an empty string means - * the edge is invalid with no error message, a non-null string specifies - * the error message, and null means the edge is valid. - * - * (code) - * graph.getEdgeValidationError = function(edge, source, target) - * { - * if (source != null && target != null && - * this.model.getValue(source) != null && - * this.model.getValue(target) != null) - * { - * if (target is not valid for source) - * { - * return 'Invalid Target'; - * } - * } - * - * // "Supercall" - * return mxGraph.prototype.getEdgeValidationError.apply(this, arguments); - * } - * (end) - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.getEdgeValidationError = function(edge, source, target) -{ - if (edge != null && !this.isAllowDanglingEdges() && (source == null || target == null)) - { - return ''; - } - - if (edge != null && this.model.getTerminal(edge, true) == null && - this.model.getTerminal(edge, false) == null) - { - return null; - } - - // Checks if we're dealing with a loop - if (!this.allowLoops && source == target && source != null) - { - return ''; - } - - // Checks if the connection is generally allowed - if (!this.isValidConnection(source, target)) - { - return ''; - } - - if (source != null && target != null) - { - var error = ''; - - // Checks if the cells are already connected - // and adds an error message if required - if (!this.multigraph) - { - var tmp = this.model.getEdgesBetween(source, target, true); - - // Checks if the source and target are not connected by another edge - if (tmp.length > 1 || (tmp.length == 1 && tmp[0] != edge)) - { - error += (mxResources.get(this.alreadyConnectedResource) || - this.alreadyConnectedResource)+'\n'; - } - } - - // Gets the number of outgoing edges from the source - // and the number of incoming edges from the target - // without counting the edge being currently changed. - var sourceOut = this.model.getDirectedEdgeCount(source, true, edge); - var targetIn = this.model.getDirectedEdgeCount(target, false, edge); - - // Checks the change against each multiplicity rule - if (this.multiplicities != null) - { - for (var i = 0; i < this.multiplicities.length; i++) - { - var err = this.multiplicities[i].check(this, edge, source, - target, sourceOut, targetIn); - - if (err != null) - { - error += err; - } - } - } - - // Validates the source and target terminals independently - var err = this.validateEdge(edge, source, target); - - if (err != null) - { - error += err; - } - - return (error.length > 0) ? error : null; - } - - return (this.allowDanglingEdges) ? null : ''; -}; - -/** - * Function: validateEdge - * - * Hook method for subclassers to return an error message for the given - * edge and terminals. This implementation returns null. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.validateEdge = function(edge, source, target) -{ - return null; -}; - -/** - * Function: validateGraph - * - * Validates the graph by validating each descendant of the given cell or - * the root of the model. Context is an object that contains the validation - * state for the complete validation run. The validation errors are - * attached to their cells using <setCellWarning>. This function returns true - * if no validation errors exist in the graph. - * - * Paramters: - * - * cell - Optional <mxCell> to start the validation recursion. Default is - * the graph root. - * context - Object that represents the global validation state. - */ -mxGraph.prototype.validateGraph = function(cell, context) -{ - cell = (cell != null) ? cell : this.model.getRoot(); - context = (context != null) ? context : new Object(); - - var isValid = true; - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var tmp = this.model.getChildAt(cell, i); - var ctx = context; - - if (this.isValidRoot(tmp)) - { - ctx = new Object(); - } - - var warn = this.validateGraph(tmp, ctx); - - if (warn != null) - { - this.setCellWarning(tmp, warn.replace(/\n/g, '<br>')); - } - else - { - this.setCellWarning(tmp, null); - } - - isValid = isValid && warn == null; - } - - var warning = ''; - - // Adds error for invalid children if collapsed (children invisible) - if (this.isCellCollapsed(cell) && !isValid) - { - warning += (mxResources.get(this.containsValidationErrorsResource) || - this.containsValidationErrorsResource)+'\n'; - } - - // Checks edges and cells using the defined multiplicities - if (this.model.isEdge(cell)) - { - warning += this.getEdgeValidationError(cell, - this.model.getTerminal(cell, true), - this.model.getTerminal(cell, false)) || ''; - } - else - { - warning += this.getCellValidationError(cell) || ''; - } - - // Checks custom validation rules - var err = this.validateCell(cell, context); - - if (err != null) - { - warning += err; - } - - // Updates the display with the warning icons - // before any potential alerts are displayed. - // LATER: Move this into addCellOverlay. Redraw - // should check if overlay was added or removed. - if (this.model.getParent(cell) == null) - { - this.view.validate(); - } - - return (warning.length > 0 || !isValid) ? warning : null; -}; - -/** - * Function: getCellValidationError - * - * Checks all <multiplicities> that cannot be enforced while the graph is - * being modified, namely, all multiplicities that require a minimum of - * 1 edge. - * - * Parameters: - * - * cell - <mxCell> for which the multiplicities should be checked. - */ -mxGraph.prototype.getCellValidationError = function(cell) -{ - var outCount = this.model.getDirectedEdgeCount(cell, true); - var inCount = this.model.getDirectedEdgeCount(cell, false); - var value = this.model.getValue(cell); - var error = ''; - - if (this.multiplicities != null) - { - for (var i = 0; i < this.multiplicities.length; i++) - { - var rule = this.multiplicities[i]; - - if (rule.source && mxUtils.isNode(value, rule.type, - rule.attr, rule.value) && ((rule.max == 0 && outCount > 0) || - (rule.min == 1 && outCount == 0) || (rule.max == 1 && outCount > 1))) - { - error += rule.countError + '\n'; - } - else if (!rule.source && mxUtils.isNode(value, rule.type, - rule.attr, rule.value) && ((rule.max == 0 && inCount > 0) || - (rule.min == 1 && inCount == 0) || (rule.max == 1 && inCount > 1))) - { - error += rule.countError + '\n'; - } - } - } - - return (error.length > 0) ? error : null; -}; - -/** - * Function: validateCell - * - * Hook method for subclassers to return an error message for the given - * cell and validation context. This implementation returns null. Any HTML - * breaks will be converted to linefeeds in the calling method. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to validate. - * context - Object that represents the global validation state. - */ -mxGraph.prototype.validateCell = function(cell, context) -{ - return null; -}; - -/** - * Group: Graph appearance - */ - -/** - * Function: getBackgroundImage - * - * Returns the <backgroundImage> as an <mxImage>. - */ -mxGraph.prototype.getBackgroundImage = function() -{ - return this.backgroundImage; -}; - -/** - * Function: setBackgroundImage - * - * Sets the new <backgroundImage>. - * - * Parameters: - * - * image - New <mxImage> to be used for the background. - */ -mxGraph.prototype.setBackgroundImage = function(image) -{ - this.backgroundImage = image; -}; - -/** - * Function: getFoldingImage - * - * Returns the <mxImage> used to display the collapsed state of - * the specified cell state. This returns null for all edges. - */ -mxGraph.prototype.getFoldingImage = function(state) -{ - if (state != null && this.foldingEnabled && !this.getModel().isEdge(state.cell)) - { - var tmp = this.isCellCollapsed(state.cell); - - if (this.isCellFoldable(state.cell, !tmp)) - { - return (tmp) ? this.collapsedImage : this.expandedImage; - } - } - - return null; -}; - -/** - * Function: convertValueToString - * - * Returns the textual representation for the given cell. This - * implementation returns the nodename or string-representation of the user - * object. - * - * Example: - * - * The following returns the label attribute from the cells user - * object if it is an XML node. - * - * (code) - * graph.convertValueToString = function(cell) - * { - * return cell.getAttribute('label'); - * } - * (end) - * - * See also: <cellLabelChanged>. - * - * Parameters: - * - * cell - <mxCell> whose textual representation should be returned. - */ -mxGraph.prototype.convertValueToString = function(cell) -{ - var value = this.model.getValue(cell); - - if (value != null) - { - if (mxUtils.isNode(value)) - { - return value.nodeName; - } - else if (typeof(value.toString) == 'function') - { - return value.toString(); - } - } - - return ''; -}; - -/** - * Function: getLabel - * - * Returns a string or DOM node that represents the label for the given - * cell. This implementation uses <convertValueToString> if <labelsVisible> - * is true. Otherwise it returns an empty string. - * - * To truncate label to match the size of the cell, the following code - * can be used. - * - * (code) - * graph.getLabel = function(cell) - * { - * var label = mxGraph.prototype.getLabel.apply(this, arguments); - * - * if (label != null && this.model.isVertex(cell)) - * { - * var geo = this.getCellGeometry(cell); - * - * if (geo != null) - * { - * var max = parseInt(geo.width / 8); - * - * if (label.length > max) - * { - * label = label.substring(0, max)+'...'; - * } - * } - * } - * return mxUtils.htmlEntities(label); - * } - * (end) - * - * A resize listener is needed in the graph to force a repaint of the label - * after a resize. - * - * (code) - * graph.addListener(mxEvent.RESIZE_CELLS, function(sender, evt) - * { - * var cells = evt.getProperty('cells'); - * - * for (var i = 0; i < cells.length; i++) - * { - * this.view.removeState(cells[i]); - * } - * }); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose label should be returned. - */ -mxGraph.prototype.getLabel = function(cell) -{ - var result = ''; - - if (this.labelsVisible && cell != null) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (!mxUtils.getValue(style, mxConstants.STYLE_NOLABEL, false)) - { - result = this.convertValueToString(cell); - } - } - - return result; -}; - -/** - * Function: isHtmlLabel - * - * Returns true if the label must be rendered as HTML markup. The default - * implementation returns <htmlLabels>. - * - * Parameters: - * - * cell - <mxCell> whose label should be displayed as HTML markup. - */ -mxGraph.prototype.isHtmlLabel = function(cell) -{ - return this.isHtmlLabels(); -}; - -/** - * Function: isHtmlLabels - * - * Returns <htmlLabels>. - */ -mxGraph.prototype.isHtmlLabels = function() -{ - return this.htmlLabels; -}; - -/** - * Function: setHtmlLabels - * - * Sets <htmlLabels>. - */ -mxGraph.prototype.setHtmlLabels = function(value) -{ - this.htmlLabels = value; -}; - -/** - * Function: isWrapping - * - * This enables wrapping for HTML labels. - * - * Returns true if no white-space CSS style directive should be used for - * displaying the given cells label. This implementation returns true if - * <mxConstants.STYLE_WHITE_SPACE> in the style of the given cell is 'wrap'. - * - * This is used as a workaround for IE ignoring the white-space directive - * of child elements if the directive appears in a parent element. It - * should be overridden to return true if a white-space directive is used - * in the HTML markup that represents the given cells label. In order for - * HTML markup to work in labels, <isHtmlLabel> must also return true - * for the given cell. - * - * Example: - * - * (code) - * graph.getLabel = function(cell) - * { - * var tmp = mxGraph.prototype.getLabel.apply(this, arguments); // "supercall" - * - * if (this.model.isEdge(cell)) - * { - * tmp = '<div style="width: 150px; white-space:normal;">'+tmp+'</div>'; - * } - * - * return tmp; - * } - * - * graph.isWrapping = function(state) - * { - * return this.model.isEdge(state.cell); - * } - * (end) - * - * Makes sure no edge label is wider than 150 pixels, otherwise the content - * is wrapped. Note: No width must be specified for wrapped vertex labels as - * the vertex defines the width in its geometry. - * - * Parameters: - * - * state - <mxCell> whose label should be wrapped. - */ -mxGraph.prototype.isWrapping = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return (style != null) ? style[mxConstants.STYLE_WHITE_SPACE] == 'wrap' : false; -}; - -/** - * Function: isLabelClipped - * - * Returns true if the overflow portion of labels should be hidden. If this - * returns true then vertex labels will be clipped to the size of the vertices. - * This implementation returns true if <mxConstants.STYLE_OVERFLOW> in the - * style of the given cell is 'hidden'. - * - * Parameters: - * - * state - <mxCell> whose label should be clipped. - */ -mxGraph.prototype.isLabelClipped = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return (style != null) ? style[mxConstants.STYLE_OVERFLOW] == 'hidden' : false; -}; - -/** - * Function: getTooltip - * - * Returns the string or DOM node that represents the tooltip for the given - * state, node and coordinate pair. This implementation checks if the given - * node is a folding icon or overlay and returns the respective tooltip. If - * this does not result in a tooltip, the handler for the cell is retrieved - * from <selectionCellsHandler> and the optional getTooltipForNode method is - * called. If no special tooltip exists here then <getTooltipForCell> is used - * with the cell in the given state as the argument to return a tooltip for the - * given state. - * - * Parameters: - * - * state - <mxCellState> whose tooltip should be returned. - * node - DOM node that is currently under the mouse. - * x - X-coordinate of the mouse. - * y - Y-coordinate of the mouse. - */ -mxGraph.prototype.getTooltip = function(state, node, x, y) -{ - var tip = null; - - if (state != null) - { - // Checks if the mouse is over the folding icon - if (state.control != null && (node == state.control.node || - node.parentNode == state.control.node)) - { - tip = this.collapseExpandResource; - tip = mxResources.get(tip) || tip; - } - - if (tip == null && state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - // LATER: Exit loop if tip is not null - if (tip == null && (node == shape.node || node.parentNode == shape.node)) - { - tip = shape.overlay.toString(); - } - }); - } - - if (tip == null) - { - var handler = this.selectionCellsHandler.getHandler(state.cell); - - if (handler != null && typeof(handler.getTooltipForNode) == 'function') - { - tip = handler.getTooltipForNode(node); - } - } - - if (tip == null) - { - tip = this.getTooltipForCell(state.cell); - } - } - - return tip; -}; - -/** - * Function: getTooltipForCell - * - * Returns the string or DOM node to be used as the tooltip for the given - * cell. This implementation uses the cells getTooltip function if it - * exists, or else it returns <convertValueToString> for the cell. - * - * Example: - * - * (code) - * graph.getTooltipForCell = function(cell) - * { - * return 'Hello, World!'; - * } - * (end) - * - * Replaces all tooltips with the string Hello, World! - * - * Parameters: - * - * cell - <mxCell> whose tooltip should be returned. - */ -mxGraph.prototype.getTooltipForCell = function(cell) -{ - var tip = null; - - if (cell != null && cell.getTooltip != null) - { - tip = cell.getTooltip(); - } - else - { - tip = this.convertValueToString(cell); - } - - return tip; -}; - -/** - * Function: getCursorForCell - * - * Returns the cursor value to be used for the CSS of the shape for the - * given cell. This implementation returns null. - * - * Parameters: - * - * cell - <mxCell> whose cursor should be returned. - */ -mxGraph.prototype.getCursorForCell = function(cell) -{ - return null; -}; - -/** - * Function: getStartSize - * - * Returns the start size of the given swimlane, that is, the width or - * height of the part that contains the title, depending on the - * horizontal style. The return value is an <mxRectangle> with either - * width or height set as appropriate. - * - * Parameters: - * - * swimlane - <mxCell> whose start size should be returned. - */ -mxGraph.prototype.getStartSize = function(swimlane) -{ - var result = new mxRectangle(); - var state = this.view.getState(swimlane); - var style = (state != null) ? state.style : this.getCellStyle(swimlane); - - if (style != null) - { - var size = parseInt(mxUtils.getValue(style, - mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE)); - - if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - result.height = size; - } - else - { - result.width = size; - } - } - - return result; -}; - -/** - * Function: getImage - * - * Returns the image URL for the given cell state. This implementation - * returns the value stored under <mxConstants.STYLE_IMAGE> in the cell - * style. - * - * Parameters: - * - * state - <mxCellState> whose image URL should be returned. - */ -mxGraph.prototype.getImage = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_IMAGE] : null; -}; - -/** - * Function: getVerticalAlign - * - * Returns the vertical alignment for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_VERTICAL_ALIGN> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose vertical alignment should be - * returned. - */ -mxGraph.prototype.getVerticalAlign = function(state) -{ - return (state != null && state.style != null) ? - (state.style[mxConstants.STYLE_VERTICAL_ALIGN] || - mxConstants.ALIGN_MIDDLE ): - null; -}; - -/** - * Function: getIndicatorColor - * - * Returns the indicator color for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_COLOR> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator color should be - * returned. - */ -mxGraph.prototype.getIndicatorColor = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_COLOR] : null; -}; - -/** - * Function: getIndicatorGradientColor - * - * Returns the indicator gradient color for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_GRADIENTCOLOR> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator gradient color should be - * returned. - */ -mxGraph.prototype.getIndicatorGradientColor = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_GRADIENTCOLOR] : null; -}; - -/** - * Function: getIndicatorShape - * - * Returns the indicator shape for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_SHAPE> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator shape should be returned. - */ -mxGraph.prototype.getIndicatorShape = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_SHAPE] : null; -}; - -/** - * Function: getIndicatorImage - * - * Returns the indicator image for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_IMAGE> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator image should be returned. - */ -mxGraph.prototype.getIndicatorImage = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_IMAGE] : null; -}; - -/** - * Function: getBorder - * - * Returns the value of <border>. - */ -mxGraph.prototype.getBorder = function() -{ - return this.border; -}; - -/** - * Function: setBorder - * - * Sets the value of <border>. - * - * Parameters: - * - * value - Positive integer that represents the border to be used. - */ -mxGraph.prototype.setBorder = function(value) -{ - this.border = value; -}; - -/** - * Function: isSwimlane - * - * Returns true if the given cell is a swimlane in the graph. A swimlane is - * a container cell with some specific behaviour. This implementation - * checks if the shape associated with the given cell is a <mxSwimlane>. - * - * Parameters: - * - * cell - <mxCell> to be checked. - */ -mxGraph.prototype.isSwimlane = function (cell) -{ - if (cell != null) - { - if (this.model.getParent(cell) != this.model.getRoot()) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (style != null && !this.model.isEdge(cell)) - { - return style[mxConstants.STYLE_SHAPE] == - mxConstants.SHAPE_SWIMLANE; - } - } - } - - return false; -}; - -/** - * Group: Graph behaviour - */ - -/** - * Function: isResizeContainer - * - * Returns <resizeContainer>. - */ -mxGraph.prototype.isResizeContainer = function() -{ - return this.resizeContainer; -}; - -/** - * Function: setResizeContainer - * - * Sets <resizeContainer>. - * - * Parameters: - * - * value - Boolean indicating if the container should be resized. - */ -mxGraph.prototype.setResizeContainer = function(value) -{ - this.resizeContainer = value; -}; - -/** - * Function: isEnabled - * - * Returns true if the graph is <enabled>. - */ -mxGraph.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Specifies if the graph should allow any interactions. This - * implementation updates <enabled>. - * - * Parameters: - * - * value - Boolean indicating if the graph should be enabled. - */ -mxGraph.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isEscapeEnabled - * - * Returns <escapeEnabled>. - */ -mxGraph.prototype.isEscapeEnabled = function() -{ - return this.escapeEnabled; -}; - -/** - * Function: setEscapeEnabled - * - * Sets <escapeEnabled>. - * - * Parameters: - * - * enabled - Boolean indicating if escape should be enabled. - */ -mxGraph.prototype.setEscapeEnabled = function(value) -{ - this.escapeEnabled = value; -}; - -/** - * Function: isInvokesStopCellEditing - * - * Returns <invokesStopCellEditing>. - */ -mxGraph.prototype.isInvokesStopCellEditing = function() -{ - return this.invokesStopCellEditing; -}; - -/** - * Function: setInvokesStopCellEditing - * - * Sets <invokesStopCellEditing>. - */ -mxGraph.prototype.setInvokesStopCellEditing = function(value) -{ - this.invokesStopCellEditing = value; -}; - -/** - * Function: isEnterStopsCellEditing - * - * Returns <enterStopsCellEditing>. - */ -mxGraph.prototype.isEnterStopsCellEditing = function() -{ - return this.enterStopsCellEditing; -}; - -/** - * Function: setEnterStopsCellEditing - * - * Sets <enterStopsCellEditing>. - */ -mxGraph.prototype.setEnterStopsCellEditing = function(value) -{ - this.enterStopsCellEditing = value; -}; - -/** - * Function: isCellLocked - * - * Returns true if the given cell may not be moved, sized, bended, - * disconnected, edited or selected. This implementation returns true for - * all vertices with a relative geometry if <locked> is false. - * - * Parameters: - * - * cell - <mxCell> whose locked state should be returned. - */ -mxGraph.prototype.isCellLocked = function(cell) -{ - var geometry = this.model.getGeometry(cell); - - return this.isCellsLocked() || (geometry != null && - this.model.isVertex(cell) && geometry.relative); -}; - -/** - * Function: isCellsLocked - * - * Returns true if the given cell may not be moved, sized, bended, - * disconnected, edited or selected. This implementation returns true for - * all vertices with a relative geometry if <locked> is false. - * - * Parameters: - * - * cell - <mxCell> whose locked state should be returned. - */ -mxGraph.prototype.isCellsLocked = function() -{ - return this.cellsLocked; -}; - -/** - * Function: setLocked - * - * Sets if any cell may be moved, sized, bended, disconnected, edited or - * selected. - * - * Parameters: - * - * value - Boolean that defines the new value for <cellsLocked>. - */ -mxGraph.prototype.setCellsLocked = function(value) -{ - this.cellsLocked = value; -}; - -/** - * Function: getCloneableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getCloneableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellCloneable(cell); - })); -}; - -/** - * Function: isCellCloneable - * - * Returns true if the given cell is cloneable. This implementation returns - * <isCellsCloneable> for all cells unless a cell style specifies - * <mxConstants.STYLE_CLONEABLE> to be 0. - * - * Parameters: - * - * cell - Optional <mxCell> whose cloneable state should be returned. - */ -mxGraph.prototype.isCellCloneable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsCloneable() && style[mxConstants.STYLE_CLONEABLE] != 0; -}; - -/** - * Function: isCellsCloneable - * - * Returns <cellsCloneable>, that is, if the graph allows cloning of cells - * by using control-drag. - */ -mxGraph.prototype.isCellsCloneable = function() -{ - return this.cellsCloneable; -}; - -/** - * Function: setCellsCloneable - * - * Specifies if the graph should allow cloning of cells by holding down the - * control key while cells are being moved. This implementation updates - * <cellsCloneable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should be cloneable. - */ -mxGraph.prototype.setCellsCloneable = function(value) -{ - this.cellsCloneable = value; -}; - -/** - * Function: getExportableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getExportableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.canExportCell(cell); - })); -}; - -/** - * Function: canExportCell - * - * Returns true if the given cell may be exported to the clipboard. This - * implementation returns <exportEnabled> for all cells. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to be exported. - */ -mxGraph.prototype.canExportCell = function(cell) -{ - return this.exportEnabled; -}; - -/** - * Function: getImportableCells - * - * Returns the cells which may be imported in the given array of cells. - */ -mxGraph.prototype.getImportableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.canImportCell(cell); - })); -}; - -/** - * Function: canImportCell - * - * Returns true if the given cell may be imported from the clipboard. - * This implementation returns <importEnabled> for all cells. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to be imported. - */ -mxGraph.prototype.canImportCell = function(cell) -{ - return this.importEnabled; -}; - -/** - * Function: isCellSelectable - * - * Returns true if the given cell is selectable. This implementation - * returns <cellsSelectable>. - * - * To add a new style for making cells (un)selectable, use the following code. - * - * (code) - * mxGraph.prototype.isCellSelectable = function(cell) - * { - * var state = this.view.getState(cell); - * var style = (state != null) ? state.style : this.getCellStyle(cell); - * - * return this.isCellsSelectable() && !this.isCellLocked(cell) && style['selectable'] != 0; - * }; - * (end) - * - * You can then use the new style as shown in this example. - * - * (code) - * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'selectable=0'); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose selectable state should be returned. - */ -mxGraph.prototype.isCellSelectable = function(cell) -{ - return this.isCellsSelectable(); -}; - -/** - * Function: isCellsSelectable - * - * Returns <cellsSelectable>. - */ -mxGraph.prototype.isCellsSelectable = function() -{ - return this.cellsSelectable; -}; - -/** - * Function: setCellsSelectable - * - * Sets <cellsSelectable>. - */ -mxGraph.prototype.setCellsSelectable = function(value) -{ - this.cellsSelectable = value; -}; - -/** - * Function: getDeletableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getDeletableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellDeletable(cell); - })); -}; - -/** - * Function: isCellDeletable - * - * Returns true if the given cell is moveable. This returns - * <cellsDeletable> for all given cells if a cells style does not specify - * <mxConstants.STYLE_DELETABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose deletable state should be returned. - */ -mxGraph.prototype.isCellDeletable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsDeletable() && style[mxConstants.STYLE_DELETABLE] != 0; -}; - -/** - * Function: isCellsDeletable - * - * Returns <cellsDeletable>. - */ -mxGraph.prototype.isCellsDeletable = function() -{ - return this.cellsDeletable; -}; - -/** - * Function: setCellsDeletable - * - * Sets <cellsDeletable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow deletion of cells. - */ -mxGraph.prototype.setCellsDeletable = function(value) -{ - this.cellsDeletable = value; -}; - -/** - * Function: isLabelMovable - * - * Returns true if the given edges's label is moveable. This returns - * <movable> for all given cells if <isLocked> does not return true - * for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose label should be moved. - */ -mxGraph.prototype.isLabelMovable = function(cell) -{ - return !this.isCellLocked(cell) && - ((this.model.isEdge(cell) && this.edgeLabelsMovable) || - (this.model.isVertex(cell) && this.vertexLabelsMovable)); -}; - -/** - * Function: getMovableCells - * - * Returns the cells which are movable in the given array of cells. - */ -mxGraph.prototype.getMovableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellMovable(cell); - })); -}; - -/** - * Function: isCellMovable - * - * Returns true if the given cell is moveable. This returns <cellsMovable> - * for all given cells if <isCellLocked> does not return true for the given - * cell and its style does not specify <mxConstants.STYLE_MOVABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose movable state should be returned. - */ -mxGraph.prototype.isCellMovable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsMovable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0; -}; - -/** - * Function: isCellsMovable - * - * Returns <cellsMovable>. - */ -mxGraph.prototype.isCellsMovable = function() -{ - return this.cellsMovable; -}; - -/** - * Function: setCellsMovable - * - * Specifies if the graph should allow moving of cells. This implementation - * updates <cellsMsovable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow moving of cells. - */ -mxGraph.prototype.setCellsMovable = function(value) -{ - this.cellsMovable = value; -}; - -/** - * Function: isGridEnabled - * - * Returns <gridEnabled> as a boolean. - */ -mxGraph.prototype.isGridEnabled = function() -{ - return this.gridEnabled; -}; - -/** - * Function: setGridEnabled - * - * Specifies if the grid should be enabled. - * - * Parameters: - * - * value - Boolean indicating if the grid should be enabled. - */ -mxGraph.prototype.setGridEnabled = function(value) -{ - this.gridEnabled = value; -}; - -/** - * Function: isPortsEnabled - * - * Returns <portsEnabled> as a boolean. - */ -mxGraph.prototype.isPortsEnabled = function() -{ - return this.portsEnabled; -}; - -/** - * Function: setPortsEnabled - * - * Specifies if the ports should be enabled. - * - * Parameters: - * - * value - Boolean indicating if the ports should be enabled. - */ -mxGraph.prototype.setPortsEnabled = function(value) -{ - this.portsEnabled = value; -}; - -/** - * Function: getGridSize - * - * Returns <gridSize>. - */ -mxGraph.prototype.getGridSize = function() -{ - return this.gridSize; -}; - -/** - * Function: setGridSize - * - * Sets <gridSize>. - */ -mxGraph.prototype.setGridSize = function(value) -{ - this.gridSize = value; -}; - -/** - * Function: getTolerance - * - * Returns <tolerance>. - */ -mxGraph.prototype.getTolerance = function() -{ - return this.tolerance; -}; - -/** - * Function: setTolerance - * - * Sets <tolerance>. - */ -mxGraph.prototype.setTolerance = function(value) -{ - this.tolerance = value; -}; - -/** - * Function: isVertexLabelsMovable - * - * Returns <vertexLabelsMovable>. - */ -mxGraph.prototype.isVertexLabelsMovable = function() -{ - return this.vertexLabelsMovable; -}; - -/** - * Function: setVertexLabelsMovable - * - * Sets <vertexLabelsMovable>. - */ -mxGraph.prototype.setVertexLabelsMovable = function(value) -{ - this.vertexLabelsMovable = value; -}; - -/** - * Function: isEdgeLabelsMovable - * - * Returns <edgeLabelsMovable>. - */ -mxGraph.prototype.isEdgeLabelsMovable = function() -{ - return this.edgeLabelsMovable; -}; - -/** - * Function: isEdgeLabelsMovable - * - * Sets <edgeLabelsMovable>. - */ -mxGraph.prototype.setEdgeLabelsMovable = function(value) -{ - this.edgeLabelsMovable = value; -}; - -/** - * Function: isSwimlaneNesting - * - * Returns <swimlaneNesting> as a boolean. - */ -mxGraph.prototype.isSwimlaneNesting = function() -{ - return this.swimlaneNesting; -}; - -/** - * Function: setSwimlaneNesting - * - * Specifies if swimlanes can be nested by drag and drop. This is only - * taken into account if dropEnabled is true. - * - * Parameters: - * - * value - Boolean indicating if swimlanes can be nested. - */ -mxGraph.prototype.setSwimlaneNesting = function(value) -{ - this.swimlaneNesting = value; -}; - -/** - * Function: isSwimlaneSelectionEnabled - * - * Returns <swimlaneSelectionEnabled> as a boolean. - */ -mxGraph.prototype.isSwimlaneSelectionEnabled = function() -{ - return this.swimlaneSelectionEnabled; -}; - -/** - * Function: setSwimlaneSelectionEnabled - * - * Specifies if swimlanes should be selected if the mouse is released - * over their content area. - * - * Parameters: - * - * value - Boolean indicating if swimlanes content areas - * should be selected when the mouse is released over them. - */ -mxGraph.prototype.setSwimlaneSelectionEnabled = function(value) -{ - this.swimlaneSelectionEnabled = value; -}; - -/** - * Function: isMultigraph - * - * Returns <multigraph> as a boolean. - */ -mxGraph.prototype.isMultigraph = function() -{ - return this.multigraph; -}; - -/** - * Function: setMultigraph - * - * Specifies if the graph should allow multiple connections between the - * same pair of vertices. - * - * Parameters: - * - * value - Boolean indicating if the graph allows multiple connections - * between the same pair of vertices. - */ -mxGraph.prototype.setMultigraph = function(value) -{ - this.multigraph = value; -}; - -/** - * Function: isAllowLoops - * - * Returns <allowLoops> as a boolean. - */ -mxGraph.prototype.isAllowLoops = function() -{ - return this.allowLoops; -}; - -/** - * Function: setAllowDanglingEdges - * - * Specifies if dangling edges are allowed, that is, if edges are allowed - * that do not have a source and/or target terminal defined. - * - * Parameters: - * - * value - Boolean indicating if dangling edges are allowed. - */ -mxGraph.prototype.setAllowDanglingEdges = function(value) -{ - this.allowDanglingEdges = value; -}; - -/** - * Function: isAllowDanglingEdges - * - * Returns <allowDanglingEdges> as a boolean. - */ -mxGraph.prototype.isAllowDanglingEdges = function() -{ - return this.allowDanglingEdges; -}; - -/** - * Function: setConnectableEdges - * - * Specifies if edges should be connectable. - * - * Parameters: - * - * value - Boolean indicating if edges should be connectable. - */ -mxGraph.prototype.setConnectableEdges = function(value) -{ - this.connectableEdges = value; -}; - -/** - * Function: isConnectableEdges - * - * Returns <connectableEdges> as a boolean. - */ -mxGraph.prototype.isConnectableEdges = function() -{ - return this.connectableEdges; -}; - -/** - * Function: setCloneInvalidEdges - * - * Specifies if edges should be inserted when cloned but not valid wrt. - * <getEdgeValidationError>. If false such edges will be silently ignored. - * - * Parameters: - * - * value - Boolean indicating if cloned invalid edges should be - * inserted into the graph or ignored. - */ -mxGraph.prototype.setCloneInvalidEdges = function(value) -{ - this.cloneInvalidEdges = value; -}; - -/** - * Function: isCloneInvalidEdges - * - * Returns <cloneInvalidEdges> as a boolean. - */ -mxGraph.prototype.isCloneInvalidEdges = function() -{ - return this.cloneInvalidEdges; -}; - -/** - * Function: setAllowLoops - * - * Specifies if loops are allowed. - * - * Parameters: - * - * value - Boolean indicating if loops are allowed. - */ -mxGraph.prototype.setAllowLoops = function(value) -{ - this.allowLoops = value; -}; - -/** - * Function: isDisconnectOnMove - * - * Returns <disconnectOnMove> as a boolean. - */ -mxGraph.prototype.isDisconnectOnMove = function() -{ - return this.disconnectOnMove; -}; - -/** - * Function: setDisconnectOnMove - * - * Specifies if edges should be disconnected when moved. (Note: Cloned - * edges are always disconnected.) - * - * Parameters: - * - * value - Boolean indicating if edges should be disconnected - * when moved. - */ -mxGraph.prototype.setDisconnectOnMove = function(value) -{ - this.disconnectOnMove = value; -}; - -/** - * Function: isDropEnabled - * - * Returns <dropEnabled> as a boolean. - */ -mxGraph.prototype.isDropEnabled = function() -{ - return this.dropEnabled; -}; - -/** - * Function: setDropEnabled - * - * Specifies if the graph should allow dropping of cells onto or into other - * cells. - * - * Parameters: - * - * dropEnabled - Boolean indicating if the graph should allow dropping - * of cells into other cells. - */ -mxGraph.prototype.setDropEnabled = function(value) -{ - this.dropEnabled = value; -}; - -/** - * Function: isSplitEnabled - * - * Returns <splitEnabled> as a boolean. - */ -mxGraph.prototype.isSplitEnabled = function() -{ - return this.splitEnabled; -}; - -/** - * Function: setSplitEnabled - * - * Specifies if the graph should allow dropping of cells onto or into other - * cells. - * - * Parameters: - * - * dropEnabled - Boolean indicating if the graph should allow dropping - * of cells into other cells. - */ -mxGraph.prototype.setSplitEnabled = function(value) -{ - this.splitEnabled = value; -}; - -/** - * Function: isCellResizable - * - * Returns true if the given cell is resizable. This returns - * <cellsResizable> for all given cells if <isCellLocked> does not return - * true for the given cell and its style does not specify - * <mxConstants.STYLE_RESIZABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose resizable state should be returned. - */ -mxGraph.prototype.isCellResizable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsResizable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_RESIZABLE] != 0; -}; - -/** - * Function: isCellsResizable - * - * Returns <cellsResizable>. - */ -mxGraph.prototype.isCellsResizable = function() -{ - return this.cellsResizable; -}; - -/** - * Function: setCellsResizable - * - * Specifies if the graph should allow resizing of cells. This - * implementation updates <cellsResizable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow resizing of - * cells. - */ -mxGraph.prototype.setCellsResizable = function(value) -{ - this.cellsResizable = value; -}; - -/** - * Function: isTerminalPointMovable - * - * Returns true if the given terminal point is movable. This is independent - * from <isCellConnectable> and <isCellDisconnectable> and controls if terminal - * points can be moved in the graph if the edge is not connected. Note that it - * is required for this to return true to connect unconnected edges. This - * implementation returns true. - * - * Parameters: - * - * cell - <mxCell> whose terminal point should be moved. - * source - Boolean indicating if the source or target terminal should be moved. - */ -mxGraph.prototype.isTerminalPointMovable = function(cell, source) -{ - return true; -}; - -/** - * Function: isCellBendable - * - * Returns true if the given cell is bendable. This returns <cellsBendable> - * for all given cells if <isLocked> does not return true for the given - * cell and its style does not specify <mxConstants.STYLE_BENDABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose bendable state should be returned. - */ -mxGraph.prototype.isCellBendable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsBendable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_BENDABLE] != 0; -}; - -/** - * Function: isCellsBendable - * - * Returns <cellsBenadable>. - */ -mxGraph.prototype.isCellsBendable = function() -{ - return this.cellsBendable; -}; - -/** - * Function: setCellsBendable - * - * Specifies if the graph should allow bending of edges. This - * implementation updates <bendable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow bending of - * edges. - */ -mxGraph.prototype.setCellsBendable = function(value) -{ - this.cellsBendable = value; -}; - -/** - * Function: isCellEditable - * - * Returns true if the given cell is editable. This returns <cellsEditable> for - * all given cells if <isCellLocked> does not return true for the given cell - * and its style does not specify <mxConstants.STYLE_EDITABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose editable state should be returned. - */ -mxGraph.prototype.isCellEditable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsEditable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_EDITABLE] != 0; -}; - -/** - * Function: isCellsEditable - * - * Returns <cellsEditable>. - */ -mxGraph.prototype.isCellsEditable = function() -{ - return this.cellsEditable; -}; - -/** - * Function: setCellsEditable - * - * Specifies if the graph should allow in-place editing for cell labels. - * This implementation updates <cellsEditable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow in-place - * editing. - */ -mxGraph.prototype.setCellsEditable = function(value) -{ - this.cellsEditable = value; -}; - -/** - * Function: isCellDisconnectable - * - * Returns true if the given cell is disconnectable from the source or - * target terminal. This returns <isCellsDisconnectable> for all given - * cells if <isCellLocked> does not return true for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose disconnectable state should be returned. - * terminal - <mxCell> that represents the source or target terminal. - * source - Boolean indicating if the source or target terminal is to be - * disconnected. - */ -mxGraph.prototype.isCellDisconnectable = function(cell, terminal, source) -{ - return this.isCellsDisconnectable() && !this.isCellLocked(cell); -}; - -/** - * Function: isCellsDisconnectable - * - * Returns <cellsDisconnectable>. - */ -mxGraph.prototype.isCellsDisconnectable = function() -{ - return this.cellsDisconnectable; -}; - -/** - * Function: setCellsDisconnectable - * - * Sets <cellsDisconnectable>. - */ -mxGraph.prototype.setCellsDisconnectable = function(value) -{ - this.cellsDisconnectable = value; -}; - -/** - * Function: isValidSource - * - * Returns true if the given cell is a valid source for new connections. - * This implementation returns true for all non-null values and is - * called by is called by <isValidConnection>. - * - * Parameters: - * - * cell - <mxCell> that represents a possible source or null. - */ -mxGraph.prototype.isValidSource = function(cell) -{ - return (cell == null && this.allowDanglingEdges) || - (cell != null && (!this.model.isEdge(cell) || - this.connectableEdges) && this.isCellConnectable(cell)); -}; - -/** - * Function: isValidTarget - * - * Returns <isValidSource> for the given cell. This is called by - * <isValidConnection>. - * - * Parameters: - * - * cell - <mxCell> that represents a possible target or null. - */ -mxGraph.prototype.isValidTarget = function(cell) -{ - return this.isValidSource(cell); -}; - -/** - * Function: isValidConnection - * - * Returns true if the given target cell is a valid target for source. - * This is a boolean implementation for not allowing connections between - * certain pairs of vertices and is called by <getEdgeValidationError>. - * This implementation returns true if <isValidSource> returns true for - * the source and <isValidTarget> returns true for the target. - * - * Parameters: - * - * source - <mxCell> that represents the source cell. - * target - <mxCell> that represents the target cell. - */ -mxGraph.prototype.isValidConnection = function(source, target) -{ - return this.isValidSource(source) && this.isValidTarget(target); -}; - -/** - * Function: setConnectable - * - * Specifies if the graph should allow new connections. This implementation - * updates <mxConnectionHandler.enabled> in <connectionHandler>. - * - * Parameters: - * - * connectable - Boolean indicating if new connections should be allowed. - */ -mxGraph.prototype.setConnectable = function(connectable) -{ - this.connectionHandler.setEnabled(connectable); -}; - -/** - * Function: isConnectable - * - * Returns true if the <connectionHandler> is enabled. - */ -mxGraph.prototype.isConnectable = function(connectable) -{ - return this.connectionHandler.isEnabled(); -}; - -/** - * Function: setTooltips - * - * Specifies if tooltips should be enabled. This implementation updates - * <mxTooltipHandler.enabled> in <tooltipHandler>. - * - * Parameters: - * - * enabled - Boolean indicating if tooltips should be enabled. - */ -mxGraph.prototype.setTooltips = function (enabled) -{ - this.tooltipHandler.setEnabled(enabled); -}; - -/** - * Function: setPanning - * - * Specifies if panning should be enabled. This implementation updates - * <mxPanningHandler.panningEnabled> in <panningHandler>. - * - * Parameters: - * - * enabled - Boolean indicating if panning should be enabled. - */ -mxGraph.prototype.setPanning = function(enabled) -{ - this.panningHandler.panningEnabled = enabled; -}; - -/** - * Function: isEditing - * - * Returns true if the given cell is currently being edited. - * If no cell is specified then this returns true if any - * cell is currently being edited. - * - * Parameters: - * - * cell - <mxCell> that should be checked. - */ -mxGraph.prototype.isEditing = function(cell) -{ - if (this.cellEditor != null) - { - var editingCell = this.cellEditor.getEditingCell(); - - return (cell == null) ? - editingCell != null : - cell == editingCell; - } - - return false; -}; - -/** - * Function: isAutoSizeCell - * - * Returns true if the size of the given cell should automatically be - * updated after a change of the label. This implementation returns - * <autoSizeCells> or checks if the cell style does specify - * <mxConstants.STYLE_AUTOSIZE> to be 1. - * - * Parameters: - * - * cell - <mxCell> that should be resized. - */ -mxGraph.prototype.isAutoSizeCell = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isAutoSizeCells() || style[mxConstants.STYLE_AUTOSIZE] == 1; -}; - -/** - * Function: isAutoSizeCells - * - * Returns <autoSizeCells>. - */ -mxGraph.prototype.isAutoSizeCells = function() -{ - return this.autoSizeCells; -}; - -/** - * Function: setAutoSizeCells - * - * Specifies if cell sizes should be automatically updated after a label - * change. This implementation sets <autoSizeCells> to the given parameter. - * - * Parameters: - * - * value - Boolean indicating if cells should be resized - * automatically. - */ -mxGraph.prototype.setAutoSizeCells = function(value) -{ - this.autoSizeCells = value; -}; - -/** - * Function: isExtendParent - * - * Returns true if the parent of the given cell should be extended if the - * child has been resized so that it overlaps the parent. This - * implementation returns <isExtendParents> if the cell is not an edge. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxGraph.prototype.isExtendParent = function(cell) -{ - return !this.getModel().isEdge(cell) && this.isExtendParents(); -}; - -/** - * Function: isExtendParents - * - * Returns <extendParents>. - */ -mxGraph.prototype.isExtendParents = function() -{ - return this.extendParents; -}; - -/** - * Function: setExtendParents - * - * Sets <extendParents>. - * - * Parameters: - * - * value - New boolean value for <extendParents>. - */ -mxGraph.prototype.setExtendParents = function(value) -{ - this.extendParents = value; -}; - -/** - * Function: isExtendParentsOnAdd - * - * Returns <extendParentsOnAdd>. - */ -mxGraph.prototype.isExtendParentsOnAdd = function() -{ - return this.extendParentsOnAdd; -}; - -/** - * Function: setExtendParentsOnAdd - * - * Sets <extendParentsOnAdd>. - * - * Parameters: - * - * value - New boolean value for <extendParentsOnAdd>. - */ -mxGraph.prototype.setExtendParentsOnAdd = function(value) -{ - this.extendParentsOnAdd = value; -}; - -/** - * Function: isConstrainChild - * - * Returns true if the given cell should be kept inside the bounds of its - * parent according to the rules defined by <getOverlap> and - * <isAllowOverlapParent>. This implementation returns false for all children - * of edges and <isConstrainChildren> otherwise. - * - * Parameters: - * - * cell - <mxCell> that should be constrained. - */ -mxGraph.prototype.isConstrainChild = function(cell) -{ - return this.isConstrainChildren() && !this.getModel().isEdge(this.getModel().getParent(cell)); - -}; - -/** - * Function: isConstrainChildren - * - * Returns <constrainChildren>. - */ -mxGraph.prototype.isConstrainChildren = function() -{ - return this.constrainChildren; -}; - -/** - * Function: setConstrainChildren - * - * Sets <constrainChildren>. - */ -mxGraph.prototype.setConstrainChildren = function(value) -{ - this.constrainChildren = value; -}; - -/** - * Function: isConstrainChildren - * - * Returns <allowNegativeCoordinates>. - */ -mxGraph.prototype.isAllowNegativeCoordinates = function() -{ - return this.allowNegativeCoordinates; -}; - -/** - * Function: setConstrainChildren - * - * Sets <allowNegativeCoordinates>. - */ -mxGraph.prototype.setAllowNegativeCoordinates = function(value) -{ - this.allowNegativeCoordinates = value; -}; - -/** - * Function: getOverlap - * - * Returns a decimal number representing the amount of the width and height - * of the given cell that is allowed to overlap its parent. A value of 0 - * means all children must stay inside the parent, 1 means the child is - * allowed to be placed outside of the parent such that it touches one of - * the parents sides. If <isAllowOverlapParent> returns false for the given - * cell, then this method returns 0. - * - * Parameters: - * - * cell - <mxCell> for which the overlap ratio should be returned. - */ -mxGraph.prototype.getOverlap = function(cell) -{ - return (this.isAllowOverlapParent(cell)) ? this.defaultOverlap : 0; -}; - -/** - * Function: isAllowOverlapParent - * - * Returns true if the given cell is allowed to be placed outside of the - * parents area. - * - * Parameters: - * - * cell - <mxCell> that represents the child to be checked. - */ -mxGraph.prototype.isAllowOverlapParent = function(cell) -{ - return false; -}; - -/** - * Function: getFoldableCells - * - * Returns the cells which are movable in the given array of cells. - */ -mxGraph.prototype.getFoldableCells = function(cells, collapse) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellFoldable(cell, collapse); - })); -}; - -/** - * Function: isCellFoldable - * - * Returns true if the given cell is foldable. This implementation - * returns true if the cell has at least one child and its style - * does not specify <mxConstants.STYLE_FOLDABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose foldable state should be returned. - */ -mxGraph.prototype.isCellFoldable = function(cell, collapse) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.model.getChildCount(cell) > 0 && style[mxConstants.STYLE_FOLDABLE] != 0; -}; - -/** - * Function: isValidDropTarget - * - * Returns true if the given cell is a valid drop target for the specified - * cells. If the given cell is an edge, then <isSplitDropTarget> is used, - * else <isParentDropTarget> is used to compute the return value. - * - * Parameters: - * - * cell - <mxCell> that represents the possible drop target. - * cells - <mxCells> that should be dropped into the target. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.isValidDropTarget = function(cell, cells, evt) -{ - return cell != null && ((this.isSplitEnabled() && - this.isSplitTarget(cell, cells, evt)) || (!this.model.isEdge(cell) && - (this.isSwimlane(cell) || (this.model.getChildCount(cell) > 0 && - !this.isCellCollapsed(cell))))); -}; - -/** - * Function: isSplitTarget - * - * Returns true if the given edge may be splitted into two edges with the - * given cell as a new terminal between the two. - * - * Parameters: - * - * target - <mxCell> that represents the edge to be splitted. - * cells - <mxCells> that should split the edge. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.isSplitTarget = function(target, cells, evt) -{ - if (this.model.isEdge(target) && cells != null && cells.length == 1 && - this.isCellConnectable(cells[0]) && this.getEdgeValidationError(target, - this.model.getTerminal(target, true), cells[0]) == null) - { - var src = this.model.getTerminal(target, true); - var trg = this.model.getTerminal(target, false); - - return (!this.model.isAncestor(cells[0], src) && - !this.model.isAncestor(cells[0], trg)); - } - - return false; -}; - -/** - * Function: getDropTarget - * - * Returns the given cell if it is a drop target for the given cells or the - * nearest ancestor that may be used as a drop target for the given cells. - * If the given array contains a swimlane and <swimlaneNesting> is false - * then this always returns null. If no cell is given, then the bottommost - * swimlane at the location of the given event is returned. - * - * This function should only be used if <isDropEnabled> returns true. - * - * Parameters: - * - * cells - Array of <mxCells> which are to be dropped onto the target. - * evt - Mouseevent for the drag and drop. - * cell - <mxCell> that is under the mousepointer. - */ -mxGraph.prototype.getDropTarget = function(cells, evt, cell) -{ - if (!this.isSwimlaneNesting()) - { - for (var i = 0; i < cells.length; i++) - { - if (this.isSwimlane(cells[i])) - { - return null; - } - } - } - - var pt = mxUtils.convertPoint(this.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - pt.x -= this.panDx; - pt.y -= this.panDy; - var swimlane = this.getSwimlaneAt(pt.x, pt.y); - - if (cell == null) - { - cell = swimlane; - } - else if (swimlane != null) - { - // Checks if the cell is an ancestor of the swimlane - // under the mouse and uses the swimlane in that case - var tmp = this.model.getParent(swimlane); - - while (tmp != null && this.isSwimlane(tmp) && tmp != cell) - { - tmp = this.model.getParent(tmp); - } - - if (tmp == cell) - { - cell = swimlane; - } - } - - while (cell != null && !this.isValidDropTarget(cell, cells, evt) && - !this.model.isLayer(cell)) - { - cell = this.model.getParent(cell); - } - - return (!this.model.isLayer(cell) && mxUtils.indexOf(cells, cell) < 0) ? cell : null; -}; - -/** - * Group: Cell retrieval - */ - -/** - * Function: getDefaultParent - * - * Returns <defaultParent> or <mxGraphView.currentRoot> or the first child - * child of <mxGraphModel.root> if both are null. The value returned by - * this function should be used as the parent for new cells (aka default - * layer). - */ -mxGraph.prototype.getDefaultParent = function() -{ - var parent = this.defaultParent; - - if (parent == null) - { - parent = this.getCurrentRoot(); - - if (parent == null) - { - var root = this.model.getRoot(); - parent = this.model.getChildAt(root, 0); - } - } - - return parent; -}; - -/** - * Function: setDefaultParent - * - * Sets the <defaultParent> to the given cell. Set this to null to return - * the first child of the root in getDefaultParent. - */ -mxGraph.prototype.setDefaultParent = function(cell) -{ - this.defaultParent = cell; -}; - -/** - * Function: getSwimlane - * - * Returns the nearest ancestor of the given cell which is a swimlane, or - * the given cell, if it is itself a swimlane. - * - * Parameters: - * - * cell - <mxCell> for which the ancestor swimlane should be returned. - */ -mxGraph.prototype.getSwimlane = function(cell) -{ - while (cell != null && !this.isSwimlane(cell)) - { - cell = this.model.getParent(cell); - } - - return cell; -}; - -/** - * Function: getSwimlaneAt - * - * Returns the bottom-most swimlane that intersects the given point (x, y) - * in the cell hierarchy that starts at the given parent. - * - * Parameters: - * - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - * parent - <mxCell> that should be used as the root of the recursion. - * Default is <defaultParent>. - */ -mxGraph.prototype.getSwimlaneAt = function (x, y, parent) -{ - parent = parent || this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(parent, i); - var result = this.getSwimlaneAt(x, y, child); - - if (result != null) - { - return result; - } - else if (this.isSwimlane(child)) - { - var state = this.view.getState(child); - - if (this.intersects(state, x, y)) - { - return child; - } - } - } - } - - return null; -}; - -/** - * Function: getCellAt - * - * Returns the bottom-most cell that intersects the given point (x, y) in - * the cell hierarchy starting at the given parent. This will also return - * swimlanes if the given location intersects the content area of the - * swimlane. If this is not desired, then the <hitsSwimlaneContent> may be - * used if the returned cell is a swimlane to determine if the location - * is inside the content area or on the actual title of the swimlane. - * - * Parameters: - * - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - * parent - <mxCell> that should be used as the root of the recursion. - * Default is <defaultParent>. - * vertices - Optional boolean indicating if vertices should be returned. - * Default is true. - * edges - Optional boolean indicating if edges should be returned. Default - * is true. - */ -mxGraph.prototype.getCellAt = function(x, y, parent, vertices, edges) -{ - vertices = (vertices != null) ? vertices : true; - edges = (edges != null) ? edges : true; - parent = (parent != null) ? parent : this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = childCount - 1; i >= 0; i--) - { - var cell = this.model.getChildAt(parent, i); - var result = this.getCellAt(x, y, cell, vertices, edges); - - if (result != null) - { - return result; - } - else if (this.isCellVisible(cell) && (edges && this.model.isEdge(cell) || - vertices && this.model.isVertex(cell))) - { - var state = this.view.getState(cell); - - if (this.intersects(state, x, y)) - { - return cell; - } - } - } - } - - return null; -}; - -/** - * Function: intersects - * - * Returns the bottom-most cell that intersects the given point (x, y) in - * the cell hierarchy that starts at the given parent. - * - * Parameters: - * - * state - <mxCellState> that represents the cell state. - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - */ -mxGraph.prototype.intersects = function(state, x, y) -{ - if (state != null) - { - var pts = state.absolutePoints; - - if (pts != null) - { - var t2 = this.tolerance * this.tolerance; - - var pt = pts[0]; - - for (var i = 1; i<pts.length; i++) - { - var next = pts[i]; - var dist = mxUtils.ptSegDistSq( - pt.x, pt.y, next.x, next.y, x, y); - - if (dist <= t2) - { - return true; - } - - pt = next; - } - } - else if (mxUtils.contains(state, x, y)) - { - return true; - } - } - - return false; -}; - -/** - * Function: hitsSwimlaneContent - * - * Returns true if the given coordinate pair is inside the content - * are of the given swimlane. - * - * Parameters: - * - * swimlane - <mxCell> that specifies the swimlane. - * x - X-coordinate of the mouse event. - * y - Y-coordinate of the mouse event. - */ -mxGraph.prototype.hitsSwimlaneContent = function(swimlane, x, y) -{ - var state = this.getView().getState(swimlane); - var size = this.getStartSize(swimlane); - - if (state != null) - { - var scale = this.getView().getScale(); - x -= state.x; - y -= state.y; - - if (size.width > 0 && x > 0 && x > size.width * scale) - { - return true; - } - else if (size.height > 0 && y > 0 && y > size.height * scale) - { - return true; - } - } - - return false; -}; - -/** - * Function: getChildVertices - * - * Returns the visible child vertices of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose children should be returned. - */ -mxGraph.prototype.getChildVertices = function(parent) -{ - return this.getChildCells(parent, true, false); -}; - -/** - * Function: getChildEdges - * - * Returns the visible child edges of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose child vertices should be returned. - */ -mxGraph.prototype.getChildEdges = function(parent) -{ - return this.getChildCells(parent, false, true); -}; - -/** - * Function: getChildCells - * - * Returns the visible child vertices or edges in the given parent. If - * vertices and edges is false, then all children are returned. - * - * Parameters: - * - * parent - <mxCell> whose children should be returned. - * vertices - Optional boolean that specifies if child vertices should - * be returned. Default is false. - * edges - Optional boolean that specifies if child edges should - * be returned. Default is false. - */ -mxGraph.prototype.getChildCells = function(parent, vertices, edges) -{ - parent = (parent != null) ? parent : this.getDefaultParent(); - vertices = (vertices != null) ? vertices : false; - edges = (edges != null) ? edges : false; - - var cells = this.model.getChildCells(parent, vertices, edges); - var result = []; - - // Filters out the non-visible child cells - for (var i = 0; i < cells.length; i++) - { - if (this.isCellVisible(cells[i])) - { - result.push(cells[i]); - } - } - - return result; -}; - -/** - * Function: getConnections - * - * Returns all visible edges connected to the given cell without loops. - * - * Parameters: - * - * cell - <mxCell> whose connections should be returned. - * parent - Optional parent of the opposite end for a connection to be - * returned. - */ -mxGraph.prototype.getConnections = function(cell, parent) -{ - return this.getEdges(cell, parent, true, true, false); -}; - -/** - * Function: getIncomingEdges - * - * Returns the visible incoming edges for the given cell. If the optional - * parent argument is specified, then only child edges of the given parent - * are returned. - * - * Parameters: - * - * cell - <mxCell> whose incoming edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - */ -mxGraph.prototype.getIncomingEdges = function(cell, parent) -{ - return this.getEdges(cell, parent, true, false, false); -}; - -/** - * Function: getOutgoingEdges - * - * Returns the visible outgoing edges for the given cell. If the optional - * parent argument is specified, then only child edges of the given parent - * are returned. - * - * Parameters: - * - * cell - <mxCell> whose outgoing edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - */ -mxGraph.prototype.getOutgoingEdges = function(cell, parent) -{ - return this.getEdges(cell, parent, false, true, false); -}; - -/** - * Function: getEdges - * - * Returns the incoming and/or outgoing edges for the given cell. - * If the optional parent argument is specified, then only edges are returned - * where the opposite is in the given parent cell. If at least one of incoming - * or outgoing is true, then loops are ignored, if both are false, then all - * edges connected to the given cell are returned including loops. - * - * Parameters: - * - * cell - <mxCell> whose edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - * incoming - Optional boolean that specifies if incoming edges should - * be included in the result. Default is true. - * outgoing - Optional boolean that specifies if outgoing edges should - * be included in the result. Default is true. - * includeLoops - Optional boolean that specifies if loops should be - * included in the result. Default is true. - * recurse - Optional boolean the specifies if the parent specified only - * need be an ancestral parent, true, or the direct parent, false. - * Default is false - */ -mxGraph.prototype.getEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse) -{ - incoming = (incoming != null) ? incoming : true; - outgoing = (outgoing != null) ? outgoing : true; - includeLoops = (includeLoops != null) ? includeLoops : true; - recurse = (recurse != null) ? recurse : false; - - var edges = []; - var isCollapsed = this.isCellCollapsed(cell); - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(cell, i); - - if (isCollapsed || !this.isCellVisible(child)) - { - edges = edges.concat(this.model.getEdges(child, incoming, outgoing)); - } - } - - edges = edges.concat(this.model.getEdges(cell, incoming, outgoing)); - var result = []; - - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - if ((includeLoops && source == target) || ((source != target) && ((incoming && - target == cell && (parent == null || this.isValidAncestor(source, parent, recurse))) || - (outgoing && source == cell && (parent == null || - this.isValidAncestor(target, parent, recurse)))))) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: isValidAncestor - * - * Returns whether or not the specified parent is a valid - * ancestor of the specified cell, either direct or indirectly - * based on whether ancestor recursion is enabled. - * - * Parameters: - * - * cell - <mxCell> the possible child cell - * parent - <mxCell> the possible parent cell - * recurse - boolean whether or not to recurse the child ancestors - */ -mxGraph.prototype.isValidAncestor = function(cell, parent, recurse) -{ - return (recurse ? this.model.isAncestor(parent, cell) : this.model - .getParent(cell) == parent); -}; - -/** - * Function: getOpposites - * - * Returns all distinct visible opposite cells for the specified terminal - * on the given edges. - * - * Parameters: - * - * edges - Array of <mxCells> that contains the edges whose opposite - * terminals should be returned. - * terminal - Terminal that specifies the end whose opposite should be - * returned. - * source - Optional boolean that specifies if source terminals should be - * included in the result. Default is true. - * targets - Optional boolean that specifies if targer terminals should be - * included in the result. Default is true. - */ -mxGraph.prototype.getOpposites = function(edges, terminal, sources, targets) -{ - sources = (sources != null) ? sources : true; - targets = (targets != null) ? targets : true; - - var terminals = []; - - // Implements set semantic on the terminals array using a string - // representation of each cell in an associative array lookup - var hash = new Object(); - - if (edges != null) - { - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - // Checks if the terminal is the source of the edge and if the - // target should be stored in the result - if (source == terminal && target != null && - target != terminal && targets) - { - var id = mxCellPath.create(target); - - if (hash[id] == null) - { - hash[id] = target; - terminals.push(target); - } - } - - // Checks if the terminal is the taget of the edge and if the - // source should be stored in the result - else if (target == terminal && source != null && - source != terminal && sources) - { - var id = mxCellPath.create(source); - - if (hash[id] == null) - { - hash[id] = source; - terminals.push(source); - } - } - } - } - - return terminals; -}; - -/** - * Function: getEdgesBetween - * - * Returns the edges between the given source and target. This takes into - * account collapsed and invisible cells and returns the connected edges - * as displayed on the screen. - * - * Parameters: - * - * source - - * target - - * directed - - */ -mxGraph.prototype.getEdgesBetween = function(source, target, directed) -{ - directed = (directed != null) ? directed : false; - var edges = this.getEdges(source); - var result = []; - - // Checks if the edge is connected to the correct - // cell and returns the first match - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var src = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var trg = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - if ((src == source && trg == target) || (!directed && src == target && trg == source)) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: getPointForEvent - * - * Returns an <mxPoint> representing the given event in the unscaled, - * non-translated coordinate space of <container> and applies the grid. - * - * Parameters: - * - * evt - Mousevent that contains the mouse pointer location. - * addOffset - Optional boolean that specifies if the position should be - * offset by half of the <gridSize>. Default is true. - */ - mxGraph.prototype.getPointForEvent = function(evt, addOffset) - { - var p = mxUtils.convertPoint(this.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - var s = this.view.scale; - var tr = this.view.translate; - var off = (addOffset != false) ? this.gridSize / 2 : 0; - - p.x = this.snap(p.x / s - tr.x - off); - p.y = this.snap(p.y / s - tr.y - off); - - return p; - }; - -/** - * Function: getCells - * - * Returns the children of the given parent that are contained in the given - * rectangle (x, y, width, height). The result is added to the optional - * result array, which is returned from the function. If no result array - * is specified then a new array is created and returned. - * - * Parameters: - * - * x - X-coordinate of the rectangle. - * y - Y-coordinate of the rectangle. - * width - Width of the rectangle. - * height - Height of the rectangle. - * parent - <mxCell> whose children should be checked. Default is - * <defaultParent>. - * result - Optional array to store the result in. - */ -mxGraph.prototype.getCells = function(x, y, width, height, parent, result) -{ - result = (result != null) ? result : []; - - if (width > 0 || height > 0) - { - var right = x + width; - var bottom = y + height; - - parent = parent || this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var cell = this.model.getChildAt(parent, i); - var state = this.view.getState(cell); - - if (this.isCellVisible(cell) && state != null) - { - if (state.x >= x && state.y >= y && - state.x + state.width <= right && - state.y + state.height <= bottom) - { - result.push(cell); - } - else - { - this.getCells(x, y, width, height, cell, result); - } - } - } - } - } - - return result; -}; - -/** - * Function: getCellsBeyond - * - * Returns the children of the given parent that are contained in the - * halfpane from the given point (x0, y0) rightwards and/or downwards - * depending on rightHalfpane and bottomHalfpane. - * - * Parameters: - * - * x0 - X-coordinate of the origin. - * y0 - Y-coordinate of the origin. - * parent - Optional <mxCell> whose children should be checked. Default is - * <defaultParent>. - * rightHalfpane - Boolean indicating if the cells in the right halfpane - * from the origin should be returned. - * bottomHalfpane - Boolean indicating if the cells in the bottom halfpane - * from the origin should be returned. - */ -mxGraph.prototype.getCellsBeyond = function(x0, y0, parent, rightHalfpane, bottomHalfpane) -{ - var result = []; - - if (rightHalfpane || bottomHalfpane) - { - if (parent == null) - { - parent = this.getDefaultParent(); - } - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(parent, i); - var state = this.view.getState(child); - - if (this.isCellVisible(child) && state != null) - { - if ((!rightHalfpane || - state.x >= x0) && - (!bottomHalfpane || - state.y >= y0)) - { - result.push(child); - } - } - } - } - } - - return result; -}; - -/** - * Function: findTreeRoots - * - * Returns all children in the given parent which do not have incoming - * edges. If the result is empty then the with the greatest difference - * between incoming and outgoing edges is returned. - * - * Parameters: - * - * parent - <mxCell> whose children should be checked. - * isolate - Optional boolean that specifies if edges should be ignored if - * the opposite end is not a child of the given parent cell. Default is - * false. - * invert - Optional boolean that specifies if outgoing or incoming edges - * should be counted for a tree root. If false then outgoing edges will be - * counted. Default is false. - */ -mxGraph.prototype.findTreeRoots = function(parent, isolate, invert) -{ - isolate = (isolate != null) ? isolate : false; - invert = (invert != null) ? invert : false; - var roots = []; - - if (parent != null) - { - var model = this.getModel(); - var childCount = model.getChildCount(parent); - var best = null; - var maxDiff = 0; - - for (var i=0; i<childCount; i++) - { - var cell = model.getChildAt(parent, i); - - if (this.model.isVertex(cell) && this.isCellVisible(cell)) - { - var conns = this.getConnections(cell, (isolate) ? parent : null); - var fanOut = 0; - var fanIn = 0; - - for (var j = 0; j < conns.length; j++) - { - var src = this.view.getVisibleTerminal(conns[j], true); - - if (src == cell) - { - fanOut++; - } - else - { - fanIn++; - } - } - - if ((invert && fanOut == 0 && fanIn > 0) || - (!invert && fanIn == 0 && fanOut > 0)) - { - roots.push(cell); - } - - var diff = (invert) ? fanIn - fanOut : fanOut - fanIn; - - if (diff > maxDiff) - { - maxDiff = diff; - best = cell; - } - } - } - - if (roots.length == 0 && best != null) - { - roots.push(best); - } - } - - return roots; -}; - -/** - * Function: traverse - * - * Traverses the (directed) graph invoking the given function for each - * visited vertex and edge. The function is invoked with the current vertex - * and the incoming edge as a parameter. This implementation makes sure - * each vertex is only visited once. The function may return false if the - * traversal should stop at the given vertex. - * - * Example: - * - * (code) - * mxLog.show(); - * var cell = graph.getSelectionCell(); - * graph.traverse(cell, false, function(vertex, edge) - * { - * mxLog.debug(graph.getLabel(vertex)); - * }); - * (end) - * - * Parameters: - * - * vertex - <mxCell> that represents the vertex where the traversal starts. - * directed - Optional boolean indicating if edges should only be traversed - * from source to target. Default is true. - * func - Visitor function that takes the current vertex and the incoming - * edge as arguments. The traversal stops if the function returns false. - * edge - Optional <mxCell> that represents the incoming edge. This is - * null for the first step of the traversal. - * visited - Optional array of cell paths for the visited cells. - */ -mxGraph.prototype.traverse = function(vertex, directed, func, edge, visited) -{ - if (func != null && vertex != null) - { - directed = (directed != null) ? directed : true; - visited = visited || []; - var id = mxCellPath.create(vertex); - - if (visited[id] == null) - { - visited[id] = vertex; - var result = func(vertex, edge); - - if (result == null || result) - { - var edgeCount = this.model.getEdgeCount(vertex); - - if (edgeCount > 0) - { - for (var i = 0; i < edgeCount; i++) - { - var e = this.model.getEdgeAt(vertex, i); - var isSource = this.model.getTerminal(e, true) == vertex; - - if (!directed || isSource) - { - var next = this.model.getTerminal(e, !isSource); - this.traverse(next, directed, func, e, visited); - } - } - } - } - } - } -}; - -/** - * Group: Selection - */ - -/** - * Function: isCellSelected - * - * Returns true if the given cell is selected. - * - * Parameters: - * - * cell - <mxCell> for which the selection state should be returned. - */ -mxGraph.prototype.isCellSelected = function(cell) -{ - return this.getSelectionModel().isSelected(cell); -}; - -/** - * Function: isSelectionEmpty - * - * Returns true if the selection is empty. - */ -mxGraph.prototype.isSelectionEmpty = function() -{ - return this.getSelectionModel().isEmpty(); -}; - -/** - * Function: clearSelection - * - * Clears the selection using <mxGraphSelectionModel.clear>. - */ -mxGraph.prototype.clearSelection = function() -{ - return this.getSelectionModel().clear(); -}; - -/** - * Function: getSelectionCount - * - * Returns the number of selected cells. - */ -mxGraph.prototype.getSelectionCount = function() -{ - return this.getSelectionModel().cells.length; -}; - -/** - * Function: getSelectionCell - * - * Returns the first cell from the array of selected <mxCells>. - */ -mxGraph.prototype.getSelectionCell = function() -{ - return this.getSelectionModel().cells[0]; -}; - -/** - * Function: getSelectionCells - * - * Returns the array of selected <mxCells>. - */ -mxGraph.prototype.getSelectionCells = function() -{ - return this.getSelectionModel().cells.slice(); -}; - -/** - * Function: setSelectionCell - * - * Sets the selection cell. - * - * Parameters: - * - * cell - <mxCell> to be selected. - */ -mxGraph.prototype.setSelectionCell = function(cell) -{ - this.getSelectionModel().setCell(cell); -}; - -/** - * Function: setSelectionCells - * - * Sets the selection cell. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - */ -mxGraph.prototype.setSelectionCells = function(cells) -{ - this.getSelectionModel().setCells(cells); -}; - -/** - * Function: addSelectionCell - * - * Adds the given cell to the selection. - * - * Parameters: - * - * cell - <mxCell> to be add to the selection. - */ -mxGraph.prototype.addSelectionCell = function(cell) -{ - this.getSelectionModel().addCell(cell); -}; - -/** - * Function: addSelectionCells - * - * Adds the given cells to the selection. - * - * Parameters: - * - * cells - Array of <mxCells> to be added to the selection. - */ -mxGraph.prototype.addSelectionCells = function(cells) -{ - this.getSelectionModel().addCells(cells); -}; - -/** - * Function: removeSelectionCell - * - * Removes the given cell from the selection. - * - * Parameters: - * - * cell - <mxCell> to be removed from the selection. - */ -mxGraph.prototype.removeSelectionCell = function(cell) -{ - this.getSelectionModel().removeCell(cell); -}; - -/** - * Function: removeSelectionCells - * - * Removes the given cells from the selection. - * - * Parameters: - * - * cells - Array of <mxCells> to be removed from the selection. - */ -mxGraph.prototype.removeSelectionCells = function(cells) -{ - this.getSelectionModel().removeCells(cells); -}; - -/** - * Function: selectRegion - * - * Selects and returns the cells inside the given rectangle for the - * specified event. - * - * Parameters: - * - * rect - <mxRectangle> that represents the region to be selected. - * evt - Mouseevent that triggered the selection. - */ -mxGraph.prototype.selectRegion = function(rect, evt) -{ - var cells = this.getCells(rect.x, rect.y, rect.width, rect.height); - this.selectCellsForEvent(cells, evt); - - return cells; -}; - -/** - * Function: selectNextCell - * - * Selects the next cell. - */ -mxGraph.prototype.selectNextCell = function() -{ - this.selectCell(true); -}; - -/** - * Function: selectPreviousCell - * - * Selects the previous cell. - */ -mxGraph.prototype.selectPreviousCell = function() -{ - this.selectCell(); -}; - -/** - * Function: selectParentCell - * - * Selects the parent cell. - */ -mxGraph.prototype.selectParentCell = function() -{ - this.selectCell(false, true); -}; - -/** - * Function: selectChildCell - * - * Selects the first child cell. - */ -mxGraph.prototype.selectChildCell = function() -{ - this.selectCell(false, false, true); -}; - -/** - * Function: selectCell - * - * Selects the next, parent, first child or previous cell, if all arguments - * are false. - * - * Parameters: - * - * isNext - Boolean indicating if the next cell should be selected. - * isParent - Boolean indicating if the parent cell should be selected. - * isChild - Boolean indicating if the first child cell should be selected. - */ -mxGraph.prototype.selectCell = function(isNext, isParent, isChild) -{ - var sel = this.selectionModel; - var cell = (sel.cells.length > 0) ? sel.cells[0] : null; - - if (sel.cells.length > 1) - { - sel.clear(); - } - - var parent = (cell != null) ? - this.model.getParent(cell) : - this.getDefaultParent(); - - var childCount = this.model.getChildCount(parent); - - if (cell == null && childCount > 0) - { - var child = this.model.getChildAt(parent, 0); - this.setSelectionCell(child); - } - else if ((cell == null || isParent) && - this.view.getState(parent) != null && - this.model.getGeometry(parent) != null) - { - if (this.getCurrentRoot() != parent) - { - this.setSelectionCell(parent); - } - } - else if (cell != null && isChild) - { - var tmp = this.model.getChildCount(cell); - - if (tmp > 0) - { - var child = this.model.getChildAt(cell, 0); - this.setSelectionCell(child); - } - } - else if (childCount > 0) - { - var i = parent.getIndex(cell); - - if (isNext) - { - i++; - var child = this.model.getChildAt(parent, i % childCount); - this.setSelectionCell(child); - } - else - { - i--; - var index = (i < 0) ? childCount - 1 : i; - var child = this.model.getChildAt(parent, index); - this.setSelectionCell(child); - } - } -}; - -/** - * Function: selectAll - * - * Selects all children of the given parent cell or the children of the - * default parent if no parent is specified. To select leaf vertices and/or - * edges use <selectCells>. - * - * Parameters: - * - * parent - Optional <mxCell> whose children should be selected. - * Default is <defaultParent>. - */ -mxGraph.prototype.selectAll = function(parent) -{ - parent = parent || this.getDefaultParent(); - - var children = this.model.getChildren(parent); - - if (children != null) - { - this.setSelectionCells(children); - } -}; - -/** - * Function: selectVertices - * - * Select all vertices inside the given parent or the default parent. - */ -mxGraph.prototype.selectVertices = function(parent) -{ - this.selectCells(true, false, parent); -}; - -/** - * Function: selectVertices - * - * Select all vertices inside the given parent or the default parent. - */ -mxGraph.prototype.selectEdges = function(parent) -{ - this.selectCells(false, true, parent); -}; - -/** - * Function: selectCells - * - * Selects all vertices and/or edges depending on the given boolean - * arguments recursively, starting at the given parent or the default - * parent if no parent is specified. Use <selectAll> to select all cells. - * - * Parameters: - * - * vertices - Boolean indicating if vertices should be selected. - * edges - Boolean indicating if edges should be selected. - * parent - Optional <mxCell> that acts as the root of the recursion. - * Default is <defaultParent>. - */ -mxGraph.prototype.selectCells = function(vertices, edges, parent) -{ - parent = parent || this.getDefaultParent(); - - var filter = mxUtils.bind(this, function(cell) - { - return this.view.getState(cell) != null && - this.model.getChildCount(cell) == 0 && - ((this.model.isVertex(cell) && vertices) || - (this.model.isEdge(cell) && edges)); - }); - - var cells = this.model.filterDescendants(filter, parent); - this.setSelectionCells(cells); -}; - -/** - * Function: selectCellForEvent - * - * Selects the given cell by either adding it to the selection or - * replacing the selection depending on whether the given mouse event is a - * toggle event. - * - * Parameters: - * - * cell - <mxCell> to be selected. - * evt - Optional mouseevent that triggered the selection. - */ -mxGraph.prototype.selectCellForEvent = function(cell, evt) -{ - var isSelected = this.isCellSelected(cell); - - if (this.isToggleEvent(evt)) - { - if (isSelected) - { - this.removeSelectionCell(cell); - } - else - { - this.addSelectionCell(cell); - } - } - else if (!isSelected || this.getSelectionCount() != 1) - { - this.setSelectionCell(cell); - } -}; - -/** - * Function: selectCellsForEvent - * - * Selects the given cells by either adding them to the selection or - * replacing the selection depending on whether the given mouse event is a - * toggle event. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - * evt - Optional mouseevent that triggered the selection. - */ -mxGraph.prototype.selectCellsForEvent = function(cells, evt) -{ - if (this.isToggleEvent(evt)) - { - this.addSelectionCells(cells); - } - else - { - this.setSelectionCells(cells); - } -}; - -/** - * Group: Selection state - */ - -/** - * Function: createHandler - * - * Creates a new handler for the given cell state. This implementation - * returns a new <mxEdgeHandler> of the corresponding cell is an edge, - * otherwise it returns an <mxVertexHandler>. - * - * Parameters: - * - * state - <mxCellState> whose handler should be created. - */ -mxGraph.prototype.createHandler = function(state) -{ - var result = null; - - if (state != null) - { - if (this.model.isEdge(state.cell)) - { - var style = this.view.getEdgeStyle(state); - - if (this.isLoop(state) || - style == mxEdgeStyle.ElbowConnector || - style == mxEdgeStyle.SideToSide || - style == mxEdgeStyle.TopToBottom) - { - result = new mxElbowEdgeHandler(state); - } - else if (style == mxEdgeStyle.SegmentConnector || - style == mxEdgeStyle.OrthConnector) - { - result = new mxEdgeSegmentHandler(state); - } - else - { - result = new mxEdgeHandler(state); - } - } - else - { - result = new mxVertexHandler(state); - } - } - - return result; -}; - -/** - * Group: Graph events - */ - -/** - * Function: addMouseListener - * - * Adds a listener to the graph event dispatch loop. The listener - * must implement the mouseDown, mouseMove and mouseUp methods - * as shown in the <mxMouseEvent> class. - * - * Parameters: - * - * listener - Listener to be added to the graph event listeners. - */ -mxGraph.prototype.addMouseListener = function(listener) -{ - if (this.mouseListeners == null) - { - this.mouseListeners = []; - } - - this.mouseListeners.push(listener); -}; - -/** - * Function: removeMouseListener - * - * Removes the specified graph listener. - * - * Parameters: - * - * listener - Listener to be removed from the graph event listeners. - */ -mxGraph.prototype.removeMouseListener = function(listener) -{ - if (this.mouseListeners != null) - { - for (var i = 0; i < this.mouseListeners.length; i++) - { - if (this.mouseListeners[i] == listener) - { - this.mouseListeners.splice(i, 1); - break; - } - } - } -}; - -/** - * Function: updateMouseEvent - * - * Sets the graphX and graphY properties if the given <mxMouseEvent> if - * required. - */ -mxGraph.prototype.updateMouseEvent = function(me) -{ - if (me.graphX == null || me.graphY == null) - { - var pt = mxUtils.convertPoint(this.container, me.getX(), me.getY()); - - me.graphX = pt.x - this.panDx; - me.graphY = pt.y - this.panDy; - } -}; - -/** - * Function: fireMouseEvent - * - * Dispatches the given event in the graph event dispatch loop. Possible - * event names are <mxEvent.MOUSE_DOWN>, <mxEvent.MOUSE_MOVE> and - * <mxEvent.MOUSE_UP>. All listeners are invoked for all events regardless - * of the consumed state of the event. - * - * Parameters: - * - * evtName - String that specifies the type of event to be dispatched. - * me - <mxMouseEvent> to be fired. - * sender - Optional sender argument. Default is this. - */ -mxGraph.prototype.fireMouseEvent = function(evtName, me, sender) -{ - if (sender == null) - { - sender = this; - } - - // Updates the graph coordinates in the event - this.updateMouseEvent(me); - - // Makes sure we have a uniform event-sequence across all - // browsers for a double click. Since evt.detail == 2 is only - // available on Firefox we use the fact that each mousedown - // must be followed by a mouseup, all out-of-sync downs - // will be dropped silently. - if (evtName == mxEvent.MOUSE_DOWN) - { - this.isMouseDown = true; - } - - // Detects and processes double taps for touch-based devices - // which do not have native double click events - if (mxClient.IS_TOUCH && this.doubleTapEnabled && evtName == mxEvent.MOUSE_DOWN) - { - var currentTime = new Date().getTime(); - - if (currentTime - this.lastTouchTime < this.doubleTapTimeout && - Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance && - Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance) - { - // FIXME: The actual editing should start on MOUSE_UP event but - // the detection of the double click should use the mouse_down event - // to make it consistent with behaviour in browser with mouse. - this.lastTouchTime = 0; - this.dblClick(me.getEvent(), me.getCell()); - - // Stop bubbling but do not consume to make sure the device - // can bring up the virtual keyboard for editing - me.getEvent().cancelBubble = true; - } - else - { - this.lastTouchX = me.getX(); - this.lastTouchY = me.getY(); - this.lastTouchTime = currentTime; - } - } - - // Workaround for IE9 standards mode ignoring tolerance for double clicks - var noDoubleClick = me.getEvent().detail/*clickCount*/ != 2; - - if (mxClient.IS_IE && document.compatMode == 'CSS1Compat') - { - if ((this.lastMouseX != null && Math.abs(this.lastMouseX - me.getX()) > this.doubleTapTolerance) || - (this.lastMouseY != null && Math.abs(this.lastMouseY - me.getY()) > this.doubleTapTolerance)) - { - noDoubleClick = true; - } - - if (evtName == mxEvent.MOUSE_UP) - { - this.lastMouseX = me.getX(); - this.lastMouseY = me.getY(); - } - } - - // Filters too many mouse ups when the mouse is down - if ((evtName != mxEvent.MOUSE_UP || this.isMouseDown) && noDoubleClick) - { - if (evtName == mxEvent.MOUSE_UP) - { - this.isMouseDown = false; - } - - if (!this.isEditing() && (mxClient.IS_OP || mxClient.IS_SF || mxClient.IS_GC || - (mxClient.IS_IE && mxClient.IS_SVG) || me.getEvent().target != this.container)) - { - if (evtName == mxEvent.MOUSE_MOVE && this.isMouseDown && this.autoScroll) - { - this.scrollPointToVisible(me.getGraphX(), me.getGraphY(), this.autoExtend); - } - - if (this.mouseListeners != null) - { - var args = [sender, me]; - - // Does not change returnValue in Opera - me.getEvent().returnValue = true; - - for (var i = 0; i < this.mouseListeners.length; i++) - { - var l = this.mouseListeners[i]; - - if (evtName == mxEvent.MOUSE_DOWN) - { - l.mouseDown.apply(l, args); - } - else if (evtName == mxEvent.MOUSE_MOVE) - { - l.mouseMove.apply(l, args); - } - else if (evtName == mxEvent.MOUSE_UP) - { - l.mouseUp.apply(l, args); - } - } - } - - // Invokes the click handler - if (evtName == mxEvent.MOUSE_UP) - { - this.click(me); - } - } - } - else if (evtName == mxEvent.MOUSE_UP) - { - this.isMouseDown = false; - } -}; - -/** - * Function: destroy - * - * Destroys the graph and all its resources. - */ -mxGraph.prototype.destroy = function() -{ - if (!this.destroyed) - { - this.destroyed = true; - - if (this.tooltipHandler != null) - { - this.tooltipHandler.destroy(); - } - - if (this.selectionCellsHandler != null) - { - this.selectionCellsHandler.destroy(); - } - - if (this.panningHandler != null) - { - this.panningHandler.destroy(); - } - - if (this.connectionHandler != null) - { - this.connectionHandler.destroy(); - } - - if (this.graphHandler != null) - { - this.graphHandler.destroy(); - } - - if (this.cellEditor != null) - { - this.cellEditor.destroy(); - } - - if (this.view != null) - { - this.view.destroy(); - } - - if (this.model != null && this.graphModelChangeListener != null) - { - this.model.removeListener(this.graphModelChangeListener); - this.graphModelChangeListener = null; - } - - this.container = null; - } -}; diff --git a/src/js/view/mxGraphSelectionModel.js b/src/js/view/mxGraphSelectionModel.js deleted file mode 100644 index 5cd16a8..0000000 --- a/src/js/view/mxGraphSelectionModel.js +++ /dev/null @@ -1,435 +0,0 @@ -/** - * $Id: mxGraphSelectionModel.js,v 1.14 2011-11-25 10:16:08 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphSelectionModel - * - * Implements the selection model for a graph. Here is a listener that handles - * all removed selection cells. - * - * (code) - * graph.getSelectionModel().addListener(mxEvent.CHANGE, function(sender, evt) - * { - * var cells = evt.getProperty('added'); - * - * for (var i = 0; i < cells.length; i++) - * { - * // Handle cells[i]... - * } - * }); - * (end) - * - * Event: mxEvent.UNDO - * - * Fires after the selection was changed in <changeSelection>. The - * <code>edit</code> property contains the <mxUndoableEdit> which contains the - * <mxSelectionChange>. - * - * Event: mxEvent.CHANGE - * - * Fires after the selection changes by executing an <mxSelectionChange>. The - * <code>added</code> and <code>removed</code> properties contain arrays of - * cells that have been added to or removed from the selection, respectively. - * - * Constructor: mxGraphSelectionModel - * - * Constructs a new graph selection model for the given <mxGraph>. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxGraphSelectionModel(graph) -{ - this.graph = graph; - this.cells = []; -}; - -/** - * Extends mxEventSource. - */ -mxGraphSelectionModel.prototype = new mxEventSource(); -mxGraphSelectionModel.prototype.constructor = mxGraphSelectionModel; - -/** - * Variable: doneResource - * - * Specifies the resource key for the status message after a long operation. - * If the resource for this key does not exist then the value is used as - * the status message. Default is 'done'. - */ -mxGraphSelectionModel.prototype.doneResource = (mxClient.language != 'none') ? 'done' : ''; - -/** - * Variable: updatingSelectionResource - * - * Specifies the resource key for the status message while the selection is - * being updated. If the resource for this key does not exist then the - * value is used as the status message. Default is 'updatingSelection'. - */ -mxGraphSelectionModel.prototype.updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : ''; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphSelectionModel.prototype.graph = null; - -/** - * Variable: singleSelection - * - * Specifies if only one selected item at a time is allowed. - * Default is false. - */ -mxGraphSelectionModel.prototype.singleSelection = false; - -/** - * Function: isSingleSelection - * - * Returns <singleSelection> as a boolean. - */ -mxGraphSelectionModel.prototype.isSingleSelection = function() -{ - return this.singleSelection; -}; - -/** - * Function: setSingleSelection - * - * Sets the <singleSelection> flag. - * - * Parameters: - * - * singleSelection - Boolean that specifies the new value for - * <singleSelection>. - */ -mxGraphSelectionModel.prototype.setSingleSelection = function(singleSelection) -{ - this.singleSelection = singleSelection; -}; - -/** - * Function: isSelected - * - * Returns true if the given <mxCell> is selected. - */ -mxGraphSelectionModel.prototype.isSelected = function(cell) -{ - if (cell != null) - { - return mxUtils.indexOf(this.cells, cell) >= 0; - } - - return false; -}; - -/** - * Function: isEmpty - * - * Returns true if no cells are currently selected. - */ -mxGraphSelectionModel.prototype.isEmpty = function() -{ - return this.cells.length == 0; -}; - -/** - * Function: clear - * - * Clears the selection and fires a <change> event if the selection was not - * empty. - */ -mxGraphSelectionModel.prototype.clear = function() -{ - this.changeSelection(null, this.cells); -}; - -/** - * Function: setCell - * - * Selects the specified <mxCell> using <setCells>. - * - * Parameters: - * - * cell - <mxCell> to be selected. - */ -mxGraphSelectionModel.prototype.setCell = function(cell) -{ - if (cell != null) - { - this.setCells([cell]); - } -}; - -/** - * Function: setCells - * - * Selects the given array of <mxCells> and fires a <change> event. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - */ -mxGraphSelectionModel.prototype.setCells = function(cells) -{ - if (cells != null) - { - if (this.singleSelection) - { - cells = [this.getFirstSelectableCell(cells)]; - } - - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.graph.isCellSelectable(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(tmp, this.cells); - } -}; - -/** - * Function: getFirstSelectableCell - * - * Returns the first selectable cell in the given array of cells. - */ -mxGraphSelectionModel.prototype.getFirstSelectableCell = function(cells) -{ - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - if (this.graph.isCellSelectable(cells[i])) - { - return cells[i]; - } - } - } - - return null; -}; - -/** - * Function: addCell - * - * Adds the given <mxCell> to the selection and fires a <select> event. - * - * Parameters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.addCell = function(cell) -{ - if (cell != null) - { - this.addCells([cell]); - } -}; - -/** - * Function: addCells - * - * Adds the given array of <mxCells> to the selection and fires a <select> - * event. - * - * Parameters: - * - * cells - Array of <mxCells> to add to the selection. - */ -mxGraphSelectionModel.prototype.addCells = function(cells) -{ - if (cells != null) - { - var remove = null; - - if (this.singleSelection) - { - remove = this.cells; - cells = [this.getFirstSelectableCell(cells)]; - } - - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (!this.isSelected(cells[i]) && - this.graph.isCellSelectable(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(tmp, remove); - } -}; - -/** - * Function: removeCell - * - * Removes the specified <mxCell> from the selection and fires a <select> - * event for the remaining cells. - * - * Parameters: - * - * cell - <mxCell> to remove from the selection. - */ -mxGraphSelectionModel.prototype.removeCell = function(cell) -{ - if (cell != null) - { - this.removeCells([cell]); - } -}; - -/** - * Function: removeCells - */ -mxGraphSelectionModel.prototype.removeCells = function(cells) -{ - if (cells != null) - { - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.isSelected(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(null, tmp); - } -}; - -/** - * Function: changeSelection - * - * Inner callback to add the specified <mxCell> to the selection. No event - * is fired in this implementation. - * - * Paramters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.changeSelection = function(added, removed) -{ - if ((added != null && - added.length > 0 && - added[0] != null) || - (removed != null && - removed.length > 0 && - removed[0] != null)) - { - var change = new mxSelectionChange(this, added, removed); - change.execute(); - var edit = new mxUndoableEdit(this, false); - edit.add(change); - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - } -}; - -/** - * Function: cellAdded - * - * Inner callback to add the specified <mxCell> to the selection. No event - * is fired in this implementation. - * - * Paramters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.cellAdded = function(cell) -{ - if (cell != null && - !this.isSelected(cell)) - { - this.cells.push(cell); - } -}; - -/** - * Function: cellRemoved - * - * Inner callback to remove the specified <mxCell> from the selection. No - * event is fired in this implementation. - * - * Parameters: - * - * cell - <mxCell> to remove from the selection. - */ -mxGraphSelectionModel.prototype.cellRemoved = function(cell) -{ - if (cell != null) - { - var index = mxUtils.indexOf(this.cells, cell); - - if (index >= 0) - { - this.cells.splice(index, 1); - } - } -}; - -/** - * Class: mxSelectionChange - * - * Action to change the current root in a view. - * - * Constructor: mxCurrentRootChange - * - * Constructs a change of the current root in the given view. - */ -function mxSelectionChange(selectionModel, added, removed) -{ - this.selectionModel = selectionModel; - this.added = (added != null) ? added.slice() : null; - this.removed = (removed != null) ? removed.slice() : null; -}; - -/** - * Function: execute - * - * Changes the current root of the view. - */ -mxSelectionChange.prototype.execute = function() -{ - var t0 = mxLog.enter('mxSelectionChange.execute'); - window.status = mxResources.get( - this.selectionModel.updatingSelectionResource) || - this.selectionModel.updatingSelectionResource; - - if (this.removed != null) - { - for (var i = 0; i < this.removed.length; i++) - { - this.selectionModel.cellRemoved(this.removed[i]); - } - } - - if (this.added != null) - { - for (var i = 0; i < this.added.length; i++) - { - this.selectionModel.cellAdded(this.added[i]); - } - } - - var tmp = this.added; - this.added = this.removed; - this.removed = tmp; - - window.status = mxResources.get(this.selectionModel.doneResource) || - this.selectionModel.doneResource; - mxLog.leave('mxSelectionChange.execute', t0); - - this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE, - 'added', this.added, 'removed', this.removed)); -}; diff --git a/src/js/view/mxGraphView.js b/src/js/view/mxGraphView.js deleted file mode 100644 index 0ef2dc8..0000000 --- a/src/js/view/mxGraphView.js +++ /dev/null @@ -1,2545 +0,0 @@ -/** - * $Id: mxGraphView.js,v 1.195 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphView - * - * Extends <mxEventSource> to implement a view for a graph. This class is in - * charge of computing the absolute coordinates for the relative child - * geometries, the points for perimeters and edge styles and keeping them - * cached in <mxCellStates> for faster retrieval. The states are updated - * whenever the model or the view state (translate, scale) changes. The scale - * and translate are honoured in the bounds. - * - * Event: mxEvent.UNDO - * - * Fires after the root was changed in <setCurrentRoot>. The <code>edit</code> - * property contains the <mxUndoableEdit> which contains the - * <mxCurrentRootChange>. - * - * Event: mxEvent.SCALE_AND_TRANSLATE - * - * Fires after the scale and translate have been changed in <scaleAndTranslate>. - * The <code>scale</code>, <code>previousScale</code>, <code>translate</code> - * and <code>previousTranslate</code> properties contain the new and previous - * scale and translate, respectively. - * - * Event: mxEvent.SCALE - * - * Fires after the scale was changed in <setScale>. The <code>scale</code> and - * <code>previousScale</code> properties contain the new and previous scale. - * - * Event: mxEvent.TRANSLATE - * - * Fires after the translate was changed in <setTranslate>. The - * <code>translate</code> and <code>previousTranslate</code> properties contain - * the new and previous value for translate. - * - * Event: mxEvent.DOWN and mxEvent.UP - * - * Fire if the current root is changed by executing an <mxCurrentRootChange>. - * The event name depends on the location of the root in the cell hierarchy - * with respect to the current root. The <code>root</code> and - * <code>previous</code> properties contain the new and previous root, - * respectively. - * - * Constructor: mxGraphView - * - * Constructs a new view for the given <mxGraph>. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxGraphView(graph) -{ - this.graph = graph; - this.translate = new mxPoint(); - this.graphBounds = new mxRectangle(); - this.states = new mxDictionary(); -}; - -/** - * Extends mxEventSource. - */ -mxGraphView.prototype = new mxEventSource(); -mxGraphView.prototype.constructor = mxGraphView; - -/** - * - */ -mxGraphView.prototype.EMPTY_POINT = new mxPoint(); - -/** - * Variable: doneResource - * - * Specifies the resource key for the status message after a long operation. - * If the resource for this key does not exist then the value is used as - * the status message. Default is 'done'. - */ -mxGraphView.prototype.doneResource = (mxClient.language != 'none') ? 'done' : ''; - -/** - * Function: updatingDocumentResource - * - * Specifies the resource key for the status message while the document is - * being updated. If the resource for this key does not exist then the - * value is used as the status message. Default is 'updatingDocument'. - */ -mxGraphView.prototype.updatingDocumentResource = (mxClient.language != 'none') ? 'updatingDocument' : ''; - -/** - * Variable: allowEval - * - * Specifies if string values in cell styles should be evaluated using - * <mxUtils.eval>. This will only be used if the string values can't be mapped - * to objects using <mxStyleRegistry>. Default is false. NOTE: Enabling this - * switch carries a possible security risk (see the section on security in - * the manual). - */ -mxGraphView.prototype.allowEval = false; - -/** - * Variable: captureDocumentGesture - * - * Specifies if a gesture should be captured when it goes outside of the - * graph container. Default is true. - */ -mxGraphView.prototype.captureDocumentGesture = true; - -/** - * Variable: rendering - * - * Specifies if shapes should be created, updated and destroyed using the - * methods of <mxCellRenderer> in <graph>. Default is true. - */ -mxGraphView.prototype.rendering = true; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphView.prototype.graph = null; - -/** - * Variable: currentRoot - * - * <mxCell> that acts as the root of the displayed cell hierarchy. - */ -mxGraphView.prototype.currentRoot = null; - -/** - * Variable: graphBounds - * - * <mxRectangle> that caches the scales, translated bounds of the current view. - */ -mxGraphView.prototype.graphBounds = null; - -/** - * Variable: scale - * - * Specifies the scale. Default is 1 (100%). - */ -mxGraphView.prototype.scale = 1; - -/** - * Variable: translate - * - * <mxPoint> that specifies the current translation. Default is a new - * empty <mxPoint>. - */ -mxGraphView.prototype.translate = null; - -/** - * Variable: updateStyle - * - * Specifies if the style should be updated in each validation step. If this - * is false then the style is only updated if the state is created or if the - * style of the cell was changed. Default is false. - */ -mxGraphView.prototype.updateStyle = false; - -/** - * Function: getGraphBounds - * - * Returns <graphBounds>. - */ -mxGraphView.prototype.getGraphBounds = function() -{ - return this.graphBounds; -}; - -/** - * Function: setGraphBounds - * - * Sets <graphBounds>. - */ -mxGraphView.prototype.setGraphBounds = function(value) -{ - this.graphBounds = value; -}; - -/** - * Function: getBounds - * - * Returns the bounds (on the screen) for the given array of <mxCells>. - * - * Parameters: - * - * cells - Array of <mxCells> to return the bounds for. - */ -mxGraphView.prototype.getBounds = function(cells) -{ - var result = null; - - if (cells != null && cells.length > 0) - { - var model = this.graph.getModel(); - - for (var i = 0; i < cells.length; i++) - { - if (model.isVertex(cells[i]) || model.isEdge(cells[i])) - { - var state = this.getState(cells[i]); - - if (state != null) - { - if (result == null) - { - result = new mxRectangle(state.x, state.y, - state.width, state.height); - } - else - { - result.add(state); - } - } - } - } - } - - return result; -}; - -/** - * Function: setCurrentRoot - * - * Sets and returns the current root and fires an <undo> event before - * calling <mxGraph.sizeDidChange>. - * - * Parameters: - * - * root - <mxCell> that specifies the root of the displayed cell hierarchy. - */ -mxGraphView.prototype.setCurrentRoot = function(root) -{ - if (this.currentRoot != root) - { - var change = new mxCurrentRootChange(this, root); - change.execute(); - var edit = new mxUndoableEdit(this, false); - edit.add(change); - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - this.graph.sizeDidChange(); - } - - return root; -}; - -/** - * Function: scaleAndTranslate - * - * Sets the scale and translation and fires a <scale> and <translate> event - * before calling <revalidate> followed by <mxGraph.sizeDidChange>. - * - * Parameters: - * - * scale - Decimal value that specifies the new scale (1 is 100%). - * dx - X-coordinate of the translation. - * dy - Y-coordinate of the translation. - */ -mxGraphView.prototype.scaleAndTranslate = function(scale, dx, dy) -{ - var previousScale = this.scale; - var previousTranslate = new mxPoint(this.translate.x, this.translate.y); - - if (this.scale != scale || this.translate.x != dx || this.translate.y != dy) - { - this.scale = scale; - - this.translate.x = dx; - this.translate.y = dy; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.SCALE_AND_TRANSLATE, - 'scale', scale, 'previousScale', previousScale, - 'translate', this.translate, 'previousTranslate', previousTranslate)); -}; - -/** - * Function: getScale - * - * Returns the <scale>. - */ -mxGraphView.prototype.getScale = function() -{ - return this.scale; -}; - -/** - * Function: setScale - * - * Sets the scale and fires a <scale> event before calling <revalidate> followed - * by <mxGraph.sizeDidChange>. - * - * Parameters: - * - * value - Decimal value that specifies the new scale (1 is 100%). - */ -mxGraphView.prototype.setScale = function(value) -{ - var previousScale = this.scale; - - if (this.scale != value) - { - this.scale = value; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.SCALE, - 'scale', value, 'previousScale', previousScale)); -}; - -/** - * Function: getTranslate - * - * Returns the <translate>. - */ -mxGraphView.prototype.getTranslate = function() -{ - return this.translate; -}; - -/** - * Function: setTranslate - * - * Sets the translation and fires a <translate> event before calling - * <revalidate> followed by <mxGraph.sizeDidChange>. The translation is the - * negative of the origin. - * - * Parameters: - * - * dx - X-coordinate of the translation. - * dy - Y-coordinate of the translation. - */ -mxGraphView.prototype.setTranslate = function(dx, dy) -{ - var previousTranslate = new mxPoint(this.translate.x, this.translate.y); - - if (this.translate.x != dx || this.translate.y != dy) - { - this.translate.x = dx; - this.translate.y = dy; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.TRANSLATE, - 'translate', this.translate, 'previousTranslate', previousTranslate)); -}; - -/** - * Function: refresh - * - * Clears the view if <currentRoot> is not null and revalidates. - */ -mxGraphView.prototype.refresh = function() -{ - if (this.currentRoot != null) - { - this.clear(); - } - - this.revalidate(); -}; - -/** - * Function: revalidate - * - * Revalidates the complete view with all cell states. - */ -mxGraphView.prototype.revalidate = function() -{ - this.invalidate(); - this.validate(); -}; - -/** - * Function: clear - * - * Removes the state of the given cell and all descendants if the given - * cell is not the current root. - * - * Parameters: - * - * cell - Optional <mxCell> for which the state should be removed. Default - * is the root of the model. - * force - Boolean indicating if the current root should be ignored for - * recursion. - */ -mxGraphView.prototype.clear = function(cell, force, recurse) -{ - var model = this.graph.getModel(); - cell = cell || model.getRoot(); - force = (force != null) ? force : false; - recurse = (recurse != null) ? recurse : true; - - this.removeState(cell); - - if (recurse && (force || cell != this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.clear(model.getChildAt(cell, i), force); - } - } - else - { - this.invalidate(cell); - } -}; - -/** - * Function: invalidate - * - * Invalidates the state of the given cell, all its descendants and - * connected edges. - * - * Parameters: - * - * cell - Optional <mxCell> to be invalidated. Default is the root of the - * model. - */ -mxGraphView.prototype.invalidate = function(cell, recurse, includeEdges, orderChanged) -{ - var model = this.graph.getModel(); - cell = cell || model.getRoot(); - recurse = (recurse != null) ? recurse : true; - includeEdges = (includeEdges != null) ? includeEdges : true; - orderChanged = (orderChanged != null) ? orderChanged : false; - - var state = this.getState(cell); - - if (state != null) - { - state.invalid = true; - - if (orderChanged) - { - state.orderChanged = true; - } - } - - // Recursively invalidates all descendants - if (recurse) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - this.invalidate(child, recurse, includeEdges, orderChanged); - } - } - - // Propagates invalidation to all connected edges - if (includeEdges) - { - var edgeCount = model.getEdgeCount(cell); - - for (var i = 0; i < edgeCount; i++) - { - this.invalidate(model.getEdgeAt(cell, i), recurse, includeEdges); - } - } -}; - -/** - * Function: validate - * - * First validates all bounds and then validates all points recursively on - * all visible cells starting at the given cell. Finally the background - * is validated using <validateBackground>. - * - * Parameters: - * - * cell - Optional <mxCell> to be used as the root of the validation. - * Default is <currentRoot> or the root of the model. - */ -mxGraphView.prototype.validate = function(cell) -{ - var t0 = mxLog.enter('mxGraphView.validate'); - window.status = mxResources.get(this.updatingDocumentResource) || - this.updatingDocumentResource; - - cell = cell || ((this.currentRoot != null) ? - this.currentRoot : - this.graph.getModel().getRoot()); - this.validateBounds(null, cell); - var graphBounds = this.validatePoints(null, cell); - - if (graphBounds == null) - { - graphBounds = new mxRectangle(); - } - - this.setGraphBounds(graphBounds); - this.validateBackground(); - - window.status = mxResources.get(this.doneResource) || - this.doneResource; - mxLog.leave('mxGraphView.validate', t0); -}; - -/** - * Function: createBackgroundPageShape - * - * Creates and returns the shape used as the background page. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the bounds of the shape. - */ -mxGraphView.prototype.createBackgroundPageShape = function(bounds) -{ - return new mxRectangleShape(bounds, 'white', 'black'); -}; - -/** - * Function: validateBackground - * - * Validates the background image. - */ -mxGraphView.prototype.validateBackground = function() -{ - var bg = this.graph.getBackgroundImage(); - - if (bg != null) - { - if (this.backgroundImage == null || this.backgroundImage.image != bg.src) - { - if (this.backgroundImage != null) - { - this.backgroundImage.destroy(); - } - - var bounds = new mxRectangle(0, 0, 1, 1); - - this.backgroundImage = new mxImageShape(bounds, bg.src); - this.backgroundImage.dialect = this.graph.dialect; - this.backgroundImage.init(this.backgroundPane); - this.backgroundImage.redraw(); - } - - this.redrawBackgroundImage(this.backgroundImage, bg); - } - else if (this.backgroundImage != null) - { - this.backgroundImage.destroy(); - this.backgroundImage = null; - } - - if (this.graph.pageVisible) - { - var bounds = this.getBackgroundPageBounds(); - - if (this.backgroundPageShape == null) - { - this.backgroundPageShape = this.createBackgroundPageShape(bounds); - this.backgroundPageShape.scale = this.scale; - this.backgroundPageShape.isShadow = true; - this.backgroundPageShape.dialect = this.graph.dialect; - this.backgroundPageShape.init(this.backgroundPane); - this.backgroundPageShape.redraw(); - - // Adds listener for double click handling on background - mxEvent.addListener(this.backgroundPageShape.node, 'dblclick', - mxUtils.bind(this, function(evt) - { - this.graph.dblClick(evt); - }) - ); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Adds basic listeners for graph event dispatching outside of the - // container and finishing the handling of a single gesture - mxEvent.addListener(this.backgroundPageShape.node, md, - mxUtils.bind(this, function(evt) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt)); - }) - ); - mxEvent.addListener(this.backgroundPageShape.node, mm, - mxUtils.bind(this, function(evt) - { - // Hides the tooltip if mouse is outside container - if (this.graph.tooltipHandler != null && - this.graph.tooltipHandler.isHideOnHover()) - { - this.graph.tooltipHandler.hide(); - } - - if (this.graph.isMouseDown && - !mxEvent.isConsumed(evt)) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(this.backgroundPageShape.node, mu, - mxUtils.bind(this, function(evt) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - }) - ); - } - else - { - this.backgroundPageShape.scale = this.scale; - this.backgroundPageShape.bounds = bounds; - this.backgroundPageShape.redraw(); - } - } - else if (this.backgroundPageShape != null) - { - this.backgroundPageShape.destroy(); - this.backgroundPageShape = null; - } -}; - -/** - * Function: getBackgroundPageBounds - * - * Returns the bounds for the background page. - */ -mxGraphView.prototype.getBackgroundPageBounds = function() -{ - var fmt = this.graph.pageFormat; - var ps = this.scale * this.graph.pageScale; - var bounds = new mxRectangle(this.scale * this.translate.x, this.scale * this.translate.y, - fmt.width * ps, fmt.height * ps); - - return bounds; -}; - -/** - * Function: redrawBackgroundImage - * - * Updates the bounds and redraws the background image. - * - * Example: - * - * If the background image should not be scaled, this can be replaced with - * the following. - * - * (code) - * mxGraphView.prototype.redrawBackground = function(backgroundImage, bg) - * { - * backgroundImage.bounds.x = this.translate.x; - * backgroundImage.bounds.y = this.translate.y; - * backgroundImage.bounds.width = bg.width; - * backgroundImage.bounds.height = bg.height; - * - * backgroundImage.redraw(); - * }; - * (end) - * - * Parameters: - * - * backgroundImage - <mxImageShape> that represents the background image. - * bg - <mxImage> that specifies the image and its dimensions. - */ -mxGraphView.prototype.redrawBackgroundImage = function(backgroundImage, bg) -{ - backgroundImage.scale = this.scale; - backgroundImage.bounds.x = this.scale * this.translate.x; - backgroundImage.bounds.y = this.scale * this.translate.y; - backgroundImage.bounds.width = this.scale * bg.width; - backgroundImage.bounds.height = this.scale * bg.height; - - backgroundImage.redraw(); -}; - -/** - * Function: validateBounds - * - * Validates the bounds of the given parent's child using the given parent - * state as the origin for the child. The validation is carried out - * recursively for all non-collapsed descendants. - * - * Parameters: - * - * parentState - <mxCellState> for the given parent. - * cell - <mxCell> for which the bounds in the state should be updated. - */ -mxGraphView.prototype.validateBounds = function(parentState, cell) -{ - var model = this.graph.getModel(); - var state = this.getState(cell, true); - - if (state != null && state.invalid) - { - if (!this.graph.isCellVisible(cell)) - { - this.removeState(cell); - } - - // Updates the cell state's origin - else if (cell != this.currentRoot && parentState != null) - { - state.absoluteOffset.x = 0; - state.absoluteOffset.y = 0; - state.origin.x = parentState.origin.x; - state.origin.y = parentState.origin.y; - var geo = this.graph.getCellGeometry(cell); - - if (geo != null) - { - if (!model.isEdge(cell)) - { - var offset = geo.offset || this.EMPTY_POINT; - - if (geo.relative) - { - state.origin.x += geo.x * parentState.width / - this.scale + offset.x; - state.origin.y += geo.y * parentState.height / - this.scale + offset.y; - } - else - { - state.absoluteOffset.x = this.scale * offset.x; - state.absoluteOffset.y = this.scale * offset.y; - state.origin.x += geo.x; - state.origin.y += geo.y; - } - } - - // Updates cell state's bounds - state.x = this.scale * (this.translate.x + state.origin.x); - state.y = this.scale * (this.translate.y + state.origin.y); - state.width = this.scale * geo.width; - state.height = this.scale * geo.height; - - if (model.isVertex(cell)) - { - this.updateVertexLabelOffset(state); - } - } - } - - // Applies child offset to origin - var offset = this.graph.getChildOffsetForCell(cell); - - if (offset != null) - { - state.origin.x += offset.x; - state.origin.y += offset.y; - } - } - - // Recursively validates the child bounds - if (state != null && (!this.graph.isCellCollapsed(cell) || - cell == this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - this.validateBounds(state, child); - } - } -}; - -/** - * Function: updateVertexLabelOffset - * - * Updates the absoluteOffset of the given vertex cell state. This takes - * into account the label position styles. - * - * Parameters: - * - * state - <mxCellState> whose absolute offset should be updated. - */ -mxGraphView.prototype.updateVertexLabelOffset = function(state) -{ - var horizontal = mxUtils.getValue(state.style, - mxConstants.STYLE_LABEL_POSITION, - mxConstants.ALIGN_CENTER); - - if (horizontal == mxConstants.ALIGN_LEFT) - { - state.absoluteOffset.x -= state.width; - } - else if (horizontal == mxConstants.ALIGN_RIGHT) - { - state.absoluteOffset.x += state.width; - } - - var vertical = mxUtils.getValue(state.style, - mxConstants.STYLE_VERTICAL_LABEL_POSITION, - mxConstants.ALIGN_MIDDLE); - - if (vertical == mxConstants.ALIGN_TOP) - { - state.absoluteOffset.y -= state.height; - } - else if (vertical == mxConstants.ALIGN_BOTTOM) - { - state.absoluteOffset.y += state.height; - } -}; - -/** - * Function: validatePoints - * - * Validates the points for the state of the given cell recursively if the - * cell is not collapsed and returns the bounding box of all visited states - * as an <mxRectangle>. - * - * Parameters: - * - * parentState - <mxCellState> for the parent cell. - * cell - <mxCell> whose points in the state should be updated. - */ -mxGraphView.prototype.validatePoints = function(parentState, cell) -{ - var model = this.graph.getModel(); - var state = this.getState(cell); - var bbox = null; - - if (state != null) - { - if (state.invalid) - { - var geo = this.graph.getCellGeometry(cell); - - if (geo != null && model.isEdge(cell)) - { - // Updates the points on the source terminal if its an edge - var source = this.getState(this.getVisibleTerminal(cell, true)); - state.setVisibleTerminalState(source, true); - - if (source != null && model.isEdge(source.cell) && - !model.isAncestor(source.cell, cell)) - { - var tmp = this.getState(model.getParent(source.cell)); - this.validatePoints(tmp, source.cell); - } - - // Updates the points on the target terminal if its an edge - var target = this.getState(this.getVisibleTerminal(cell, false)); - state.setVisibleTerminalState(target, false); - - if (target != null && model.isEdge(target.cell) && - !model.isAncestor(target.cell, cell)) - { - var tmp = this.getState(model.getParent(target.cell)); - this.validatePoints(tmp, target.cell); - } - - this.updateFixedTerminalPoints(state, source, target); - this.updatePoints(state, geo.points, source, target); - this.updateFloatingTerminalPoints(state, source, target); - this.updateEdgeBounds(state); - this.updateEdgeLabelOffset(state); - } - else if (geo != null && geo.relative && parentState != null && - model.isEdge(parentState.cell)) - { - var origin = this.getPoint(parentState, geo); - - if (origin != null) - { - state.x = origin.x; - state.y = origin.y; - - origin.x = (origin.x / this.scale) - this.translate.x; - origin.y = (origin.y / this.scale) - this.translate.y; - state.origin = origin; - - this.childMoved(parentState, state); - } - } - - state.invalid = false; - - if (cell != this.currentRoot) - { - // NOTE: Label bounds currently ignored if rendering is false - this.graph.cellRenderer.redraw(state, false, this.isRendering()); - } - } - - if (model.isEdge(cell) || model.isVertex(cell)) - { - if (state.shape != null && state.shape.boundingBox != null) - { - bbox = state.shape.boundingBox.clone(); - } - - if (state.text != null && !this.graph.isLabelClipped(state.cell)) - { - // Adds label bounding box to graph bounds - if (state.text.boundingBox != null) - { - if (bbox != null) - { - bbox.add(state.text.boundingBox); - } - else - { - bbox = state.text.boundingBox.clone(); - } - } - } - } - } - - if (state != null && (!this.graph.isCellCollapsed(cell) || - cell == this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - var bounds = this.validatePoints(state, child); - - if (bounds != null) - { - if (bbox == null) - { - bbox = bounds; - } - else - { - bbox.add(bounds); - } - } - } - } - - return bbox; -}; - -/** - * Function: childMoved - * - * Invoked when a child state was moved as a result of late evaluation - * of its position. This is invoked for relative edge children whose - * position can only be determined after the points of the parent edge - * are updated in validatePoints, and validates the bounds of all - * descendants of the child using validateBounds. - * - * Parameters: - * - * parent - <mxCellState> that represents the parent state. - * child - <mxCellState> that represents the child state. - */ -mxGraphView.prototype.childMoved = function(parent, child) -{ - var cell = child.cell; - - // Children of relative edge children need to validate - // their bounds after their parent state was updated - if (!this.graph.isCellCollapsed(cell) || cell == this.currentRoot) - { - var model = this.graph.getModel(); - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.validateBounds(child, model.getChildAt(cell, i)); - } - } -}; - -/** - * Function: updateFixedTerminalPoints - * - * Sets the initial absolute terminal points in the given state before the edge - * style is computed. - * - * Parameters: - * - * edge - <mxCellState> whose initial terminal points should be updated. - * source - <mxCellState> which represents the source terminal. - * target - <mxCellState> which represents the target terminal. - */ -mxGraphView.prototype.updateFixedTerminalPoints = function(edge, source, target) -{ - this.updateFixedTerminalPoint(edge, source, true, - this.graph.getConnectionConstraint(edge, source, true)); - this.updateFixedTerminalPoint(edge, target, false, - this.graph.getConnectionConstraint(edge, target, false)); -}; - -/** - * Function: updateFixedTerminalPoint - * - * Sets the fixed source or target terminal point on the given edge. - * - * Parameters: - * - * edge - <mxCellState> whose terminal point should be updated. - * terminal - <mxCellState> which represents the actual terminal. - * source - Boolean that specifies if the terminal is the source. - * constraint - <mxConnectionConstraint> that specifies the connection. - */ -mxGraphView.prototype.updateFixedTerminalPoint = function(edge, terminal, source, constraint) -{ - var pt = null; - - if (constraint != null) - { - pt = this.graph.getConnectionPoint(terminal, constraint); - } - - if (pt == null && terminal == null) - { - var s = this.scale; - var tr = this.translate; - var orig = edge.origin; - var geo = this.graph.getCellGeometry(edge.cell); - pt = geo.getTerminalPoint(source); - - if (pt != null) - { - pt = new mxPoint(s * (tr.x + pt.x + orig.x), - s * (tr.y + pt.y + orig.y)); - } - } - - edge.setAbsoluteTerminalPoint(pt, source); -}; - -/** - * Function: updatePoints - * - * Updates the absolute points in the given state using the specified array - * of <mxPoints> as the relative points. - * - * Parameters: - * - * edge - <mxCellState> whose absolute points should be updated. - * points - Array of <mxPoints> that constitute the relative points. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - */ -mxGraphView.prototype.updatePoints = function(edge, points, source, target) -{ - if (edge != null) - { - var pts = []; - pts.push(edge.absolutePoints[0]); - var edgeStyle = this.getEdgeStyle(edge, points, source, target); - - if (edgeStyle != null) - { - var src = this.getTerminalPort(edge, source, true); - var trg = this.getTerminalPort(edge, target, false); - - edgeStyle(edge, src, trg, points, pts); - } - else if (points != null) - { - for (var i = 0; i < points.length; i++) - { - if (points[i] != null) - { - var pt = mxUtils.clone(points[i]); - pts.push(this.transformControlPoint(edge, pt)); - } - } - } - - var tmp = edge.absolutePoints; - pts.push(tmp[tmp.length-1]); - - edge.absolutePoints = pts; - } -}; - -/** - * Function: transformControlPoint - * - * Transforms the given control point to an absolute point. - */ -mxGraphView.prototype.transformControlPoint = function(state, pt) -{ - var orig = state.origin; - - return new mxPoint(this.scale * (pt.x + this.translate.x + orig.x), - this.scale * (pt.y + this.translate.y + orig.y)); -}; - -/** - * Function: getEdgeStyle - * - * Returns the edge style function to be used to render the given edge - * state. - */ -mxGraphView.prototype.getEdgeStyle = function(edge, points, source, target) -{ - var edgeStyle = (source != null && source == target) ? - mxUtils.getValue(edge.style, mxConstants.STYLE_LOOP, - this.graph.defaultLoopStyle) : - (!mxUtils.getValue(edge.style, - mxConstants.STYLE_NOEDGESTYLE, false) ? - edge.style[mxConstants.STYLE_EDGE] : - null); - - // Converts string values to objects - if (typeof(edgeStyle) == "string") - { - var tmp = mxStyleRegistry.getValue(edgeStyle); - - if (tmp == null && this.isAllowEval()) - { - tmp = mxUtils.eval(edgeStyle); - } - - edgeStyle = tmp; - } - - if (typeof(edgeStyle) == "function") - { - return edgeStyle; - } - - return null; -}; - -/** - * Function: updateFloatingTerminalPoints - * - * Updates the terminal points in the given state after the edge style was - * computed for the edge. - * - * Parameters: - * - * state - <mxCellState> whose terminal points should be updated. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - */ -mxGraphView.prototype.updateFloatingTerminalPoints = function(state, source, target) -{ - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length - 1]; - - if (pe == null && target != null) - { - this.updateFloatingTerminalPoint(state, target, source, false); - } - - if (p0 == null && source != null) - { - this.updateFloatingTerminalPoint(state, source, target, true); - } -}; - -/** - * Function: updateFloatingTerminalPoint - * - * Updates the absolute terminal point in the given state for the given - * start and end state, where start is the source if source is true. - * - * Parameters: - * - * edge - <mxCellState> whose terminal point should be updated. - * start - <mxCellState> for the terminal on "this" side of the edge. - * end - <mxCellState> for the terminal on the other side of the edge. - * source - Boolean indicating if start is the source terminal state. - */ -mxGraphView.prototype.updateFloatingTerminalPoint = function(edge, start, end, source) -{ - start = this.getTerminalPort(edge, start, source); - var next = this.getNextPoint(edge, end, source); - - var alpha = mxUtils.toRadians(Number(start.style[mxConstants.STYLE_ROTATION] || '0')); - var center = new mxPoint(start.getCenterX(), start.getCenterY()); - - if (alpha != 0) - { - var cos = Math.cos(-alpha); - var sin = Math.sin(-alpha); - next = mxUtils.getRotatedPoint(next, cos, sin, center); - } - - var border = parseFloat(edge.style[mxConstants.STYLE_PERIMETER_SPACING] || 0); - border += parseFloat(edge.style[(source) ? - mxConstants.STYLE_SOURCE_PERIMETER_SPACING : - mxConstants.STYLE_TARGET_PERIMETER_SPACING] || 0); - var pt = this.getPerimeterPoint(start, next, this.graph.isOrthogonal(edge), border); - - if (alpha != 0) - { - var cos = Math.cos(alpha); - var sin = Math.sin(alpha); - pt = mxUtils.getRotatedPoint(pt, cos, sin, center); - } - - edge.setAbsoluteTerminalPoint(pt, source); -}; - -/** - * Function: getTerminalPort - * - * Returns an <mxCellState> that represents the source or target terminal or - * port for the given edge. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the edge. - * terminal - <mxCellState> that represents the terminal. - * source - Boolean indicating if the given terminal is the source terminal. - */ -mxGraphView.prototype.getTerminalPort = function(state, terminal, source) -{ - var key = (source) ? mxConstants.STYLE_SOURCE_PORT : - mxConstants.STYLE_TARGET_PORT; - var id = mxUtils.getValue(state.style, key); - - if (id != null) - { - var tmp = this.getState(this.graph.getModel().getCell(id)); - - // Only uses ports where a cell state exists - if (tmp != null) - { - terminal = tmp; - } - } - - return terminal; -}; - -/** - * Function: getPerimeterPoint - * - * Returns an <mxPoint> that defines the location of the intersection point between - * the perimeter and the line between the center of the shape and the given point. - * - * Parameters: - * - * terminal - <mxCellState> for the source or target terminal. - * next - <mxPoint> that lies outside of the given terminal. - * orthogonal - Boolean that specifies if the orthogonal projection onto - * the perimeter should be returned. If this is false then the intersection - * of the perimeter and the line between the next and the center point is - * returned. - * border - Optional border between the perimeter and the shape. - */ -mxGraphView.prototype.getPerimeterPoint = function(terminal, next, orthogonal, border) -{ - var point = null; - - if (terminal != null) - { - var perimeter = this.getPerimeterFunction(terminal); - - if (perimeter != null && next != null) - { - var bounds = this.getPerimeterBounds(terminal, border); - - if (bounds.width > 0 || bounds.height > 0) - { - point = perimeter(bounds, terminal, next, orthogonal); - } - } - - if (point == null) - { - point = this.getPoint(terminal); - } - } - - return point; -}; - -/** - * Function: getRoutingCenterX - * - * Returns the x-coordinate of the center point for automatic routing. - */ -mxGraphView.prototype.getRoutingCenterX = function (state) -{ - var f = (state.style != null) ? parseFloat(state.style - [mxConstants.STYLE_ROUTING_CENTER_X]) || 0 : 0; - - return state.getCenterX() + f * state.width; -}; - -/** - * Function: getRoutingCenterY - * - * Returns the y-coordinate of the center point for automatic routing. - */ -mxGraphView.prototype.getRoutingCenterY = function (state) -{ - var f = (state.style != null) ? parseFloat(state.style - [mxConstants.STYLE_ROUTING_CENTER_Y]) || 0 : 0; - - return state.getCenterY() + f * state.height; -}; - -/** - * Function: getPerimeterBounds - * - * Returns the perimeter bounds for the given terminal, edge pair as an - * <mxRectangle>. - * - * If you have a model where each terminal has a relative child that should - * act as the graphical endpoint for a connection from/to the terminal, then - * this method can be replaced as follows: - * - * (code) - * var oldGetPerimeterBounds = mxGraphView.prototype.getPerimeterBounds; - * mxGraphView.prototype.getPerimeterBounds = function(terminal, edge, isSource) - * { - * var model = this.graph.getModel(); - * var childCount = model.getChildCount(terminal.cell); - * - * if (childCount > 0) - * { - * var child = model.getChildAt(terminal.cell, 0); - * var geo = model.getGeometry(child); - * - * if (geo != null && - * geo.relative) - * { - * var state = this.getState(child); - * - * if (state != null) - * { - * terminal = state; - * } - * } - * } - * - * return oldGetPerimeterBounds.apply(this, arguments); - * }; - * (end) - * - * Parameters: - * - * terminal - <mxCellState> that represents the terminal. - * border - Number that adds a border between the shape and the perimeter. - */ -mxGraphView.prototype.getPerimeterBounds = function(terminal, border) -{ - border = (border != null) ? border : 0; - - if (terminal != null) - { - border += parseFloat(terminal.style[mxConstants.STYLE_PERIMETER_SPACING] || 0); - } - - return terminal.getPerimeterBounds(border * this.scale); -}; - -/** - * Function: getPerimeterFunction - * - * Returns the perimeter function for the given state. - */ -mxGraphView.prototype.getPerimeterFunction = function(state) -{ - var perimeter = state.style[mxConstants.STYLE_PERIMETER]; - - // Converts string values to objects - if (typeof(perimeter) == "string") - { - var tmp = mxStyleRegistry.getValue(perimeter); - - if (tmp == null && this.isAllowEval()) - { - tmp = mxUtils.eval(perimeter); - } - - perimeter = tmp; - } - - if (typeof(perimeter) == "function") - { - return perimeter; - } - - return null; -}; - -/** - * Function: getNextPoint - * - * Returns the nearest point in the list of absolute points or the center - * of the opposite terminal. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - * opposite - <mxCellState> that represents the opposite terminal. - * source - Boolean indicating if the next point for the source or target - * should be returned. - */ -mxGraphView.prototype.getNextPoint = function(edge, opposite, source) -{ - var pts = edge.absolutePoints; - var point = null; - - if (pts != null && (source || pts.length > 2 || opposite == null)) - { - var count = pts.length; - point = pts[(source) ? Math.min(1, count - 1) : Math.max(0, count - 2)]; - } - - if (point == null && opposite != null) - { - point = new mxPoint(opposite.getCenterX(), opposite.getCenterY()); - } - - return point; -}; - -/** - * Function: getVisibleTerminal - * - * Returns the nearest ancestor terminal that is visible. The edge appears - * to be connected to this terminal on the display. The result of this method - * is cached in <mxCellState.getVisibleTerminalState>. - * - * Parameters: - * - * edge - <mxCell> whose visible terminal should be returned. - * source - Boolean that specifies if the source or target terminal - * should be returned. - */ -mxGraphView.prototype.getVisibleTerminal = function(edge, source) -{ - var model = this.graph.getModel(); - var result = model.getTerminal(edge, source); - var best = result; - - while (result != null && result != this.currentRoot) - { - if (!this.graph.isCellVisible(best) || this.graph.isCellCollapsed(result)) - { - best = result; - } - - result = model.getParent(result); - } - - // Checks if the result is not a layer - if (model.getParent(best) == model.getRoot()) - { - best = null; - } - - return best; -}; - -/** - * Function: updateEdgeBounds - * - * Updates the given state using the bounding box of the absolute points. - * Also updates <mxCellState.terminalDistance>, <mxCellState.length> and - * <mxCellState.segments>. - * - * Parameters: - * - * state - <mxCellState> whose bounds should be updated. - */ -mxGraphView.prototype.updateEdgeBounds = function(state) -{ - var points = state.absolutePoints; - state.length = 0; - - if (points != null && points.length > 0) - { - var p0 = points[0]; - var pe = points[points.length - 1]; - - if (p0 == null || pe == null) - { - // Drops the edge state if the edge is not the root - if (state.cell != this.currentRoot) - { - // Note: This condition normally occurs if a connected edge has a - // null-terminal, ie. edge.source == null or edge.target == null, - // and no corresponding terminal point defined, which happens for - // example if the terminal-id was not resolved at cell decoding time. - this.clear(state.cell, true); - } - } - else - { - if (p0.x != pe.x || p0.y != pe.y) - { - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - state.terminalDistance = Math.sqrt(dx * dx + dy * dy); - } - else - { - state.terminalDistance = 0; - } - - var length = 0; - var segments = []; - var pt = p0; - - if (pt != null) - { - var minX = pt.x; - var minY = pt.y; - var maxX = minX; - var maxY = minY; - - for (var i = 1; i < points.length; i++) - { - var tmp = points[i]; - - if (tmp != null) - { - var dx = pt.x - tmp.x; - var dy = pt.y - tmp.y; - - var segment = Math.sqrt(dx * dx + dy * dy); - segments.push(segment); - length += segment; - - pt = tmp; - - minX = Math.min(pt.x, minX); - minY = Math.min(pt.y, minY); - maxX = Math.max(pt.x, maxX); - maxY = Math.max(pt.y, maxY); - } - } - - state.length = length; - state.segments = segments; - - var markerSize = 1; // TODO: include marker size - - state.x = minX; - state.y = minY; - state.width = Math.max(markerSize, maxX - minX); - state.height = Math.max(markerSize, maxY - minY); - } - } - } -}; - -/** - * Function: getPoint - * - * Returns the absolute point on the edge for the given relative - * <mxGeometry> as an <mxPoint>. The edge is represented by the given - * <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the parent edge. - * geometry - <mxGeometry> that represents the relative location. - */ -mxGraphView.prototype.getPoint = function(state, geometry) -{ - var x = state.getCenterX(); - var y = state.getCenterY(); - - if (state.segments != null && (geometry == null || geometry.relative)) - { - var gx = (geometry != null) ? geometry.x / 2 : 0; - var pointCount = state.absolutePoints.length; - var dist = (gx + 0.5) * state.length; - var segment = state.segments[0]; - var length = 0; - var index = 1; - - while (dist > length + segment && index < pointCount-1) - { - length += segment; - segment = state.segments[index++]; - } - - var factor = (segment == 0) ? 0 : (dist - length) / segment; - var p0 = state.absolutePoints[index-1]; - var pe = state.absolutePoints[index]; - - if (p0 != null && pe != null) - { - var gy = 0; - var offsetX = 0; - var offsetY = 0; - - if (geometry != null) - { - gy = geometry.y; - var offset = geometry.offset; - - if (offset != null) - { - offsetX = offset.x; - offsetY = offset.y; - } - } - - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var nx = (segment == 0) ? 0 : dy / segment; - var ny = (segment == 0) ? 0 : dx / segment; - - x = p0.x + dx * factor + (nx * gy + offsetX) * this.scale; - y = p0.y + dy * factor - (ny * gy - offsetY) * this.scale; - } - } - else if (geometry != null) - { - var offset = geometry.offset; - - if (offset != null) - { - x += offset.x; - y += offset.y; - } - } - - return new mxPoint(x, y); -}; - -/** - * Function: getRelativePoint - * - * Gets the relative point that describes the given, absolute label - * position for the given edge state. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the parent edge. - * x - Specifies the x-coordinate of the absolute label location. - * y - Specifies the y-coordinate of the absolute label location. - */ -mxGraphView.prototype.getRelativePoint = function(edgeState, x, y) -{ - var model = this.graph.getModel(); - var geometry = model.getGeometry(edgeState.cell); - - if (geometry != null) - { - var pointCount = edgeState.absolutePoints.length; - - if (geometry.relative && pointCount > 1) - { - var totalLength = edgeState.length; - var segments = edgeState.segments; - - // Works which line segment the point of the label is closest to - var p0 = edgeState.absolutePoints[0]; - var pe = edgeState.absolutePoints[1]; - var minDist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); - - var index = 0; - var tmp = 0; - var length = 0; - - for (var i = 2; i < pointCount; i++) - { - tmp += segments[i - 2]; - pe = edgeState.absolutePoints[i]; - var dist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); - - if (dist <= minDist) - { - minDist = dist; - index = i - 1; - length = tmp; - } - - p0 = pe; - } - - var seg = segments[index]; - p0 = edgeState.absolutePoints[index]; - pe = edgeState.absolutePoints[index + 1]; - - var x2 = p0.x; - var y2 = p0.y; - - var x1 = pe.x; - var y1 = pe.y; - - var px = x; - var py = y; - - var xSegment = x2 - x1; - var ySegment = y2 - y1; - - px -= x1; - py -= y1; - var projlenSq = 0; - - px = xSegment - px; - py = ySegment - py; - var dotprod = px * xSegment + py * ySegment; - - if (dotprod <= 0.0) - { - projlenSq = 0; - } - else - { - projlenSq = dotprod * dotprod - / (xSegment * xSegment + ySegment * ySegment); - } - - var projlen = Math.sqrt(projlenSq); - - if (projlen > seg) - { - projlen = seg; - } - - var yDistance = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, pe - .x, pe.y, x, y)); - var direction = mxUtils.relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y); - - if (direction == -1) - { - yDistance = -yDistance; - } - - // Constructs the relative point for the label - return new mxPoint(((totalLength / 2 - length - projlen) / totalLength) * -2, - yDistance / this.scale); - } - } - - return new mxPoint(); -}; - -/** - * Function: updateEdgeLabelOffset - * - * Updates <mxCellState.absoluteOffset> for the given state. The absolute - * offset is normally used for the position of the edge label. Is is - * calculated from the geometry as an absolute offset from the center - * between the two endpoints if the geometry is absolute, or as the - * relative distance between the center along the line and the absolute - * orthogonal distance if the geometry is relative. - * - * Parameters: - * - * state - <mxCellState> whose absolute offset should be updated. - */ -mxGraphView.prototype.updateEdgeLabelOffset = function(state) -{ - var points = state.absolutePoints; - - state.absoluteOffset.x = state.getCenterX(); - state.absoluteOffset.y = state.getCenterY(); - - if (points != null && points.length > 0 && state.segments != null) - { - var geometry = this.graph.getCellGeometry(state.cell); - - if (geometry.relative) - { - var offset = this.getPoint(state, geometry); - - if (offset != null) - { - state.absoluteOffset = offset; - } - } - else - { - var p0 = points[0]; - var pe = points[points.length - 1]; - - if (p0 != null && pe != null) - { - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var x0 = 0; - var y0 = 0; - - var off = geometry.offset; - - if (off != null) - { - x0 = off.x; - y0 = off.y; - } - - var x = p0.x + dx / 2 + x0 * this.scale; - var y = p0.y + dy / 2 + y0 * this.scale; - - state.absoluteOffset.x = x; - state.absoluteOffset.y = y; - } - } - } -}; - -/** - * Function: getState - * - * Returns the <mxCellState> for the given cell. If create is true, then - * the state is created if it does not yet exist. - * - * Parameters: - * - * cell - <mxCell> for which the <mxCellState> should be returned. - * create - Optional boolean indicating if a new state should be created - * if it does not yet exist. Default is false. - */ -mxGraphView.prototype.getState = function(cell, create) -{ - create = create || false; - var state = null; - - if (cell != null) - { - state = this.states.get(cell); - - if (this.graph.isCellVisible(cell)) - { - if (state == null && create && this.graph.isCellVisible(cell)) - { - state = this.createState(cell); - this.states.put(cell, state); - } - else if (create && state != null && this.updateStyle) - { - state.style = this.graph.getCellStyle(cell); - } - } - } - - return state; -}; - -/** - * Function: isRendering - * - * Returns <rendering>. - */ -mxGraphView.prototype.isRendering = function() -{ - return this.rendering; -}; - -/** - * Function: setRendering - * - * Sets <rendering>. - */ -mxGraphView.prototype.setRendering = function(value) -{ - this.rendering = value; -}; - -/** - * Function: isAllowEval - * - * Returns <allowEval>. - */ -mxGraphView.prototype.isAllowEval = function() -{ - return this.allowEval; -}; - -/** - * Function: setAllowEval - * - * Sets <allowEval>. - */ -mxGraphView.prototype.setAllowEval = function(value) -{ - this.allowEval = value; -}; - -/** - * Function: getStates - * - * Returns <states>. - */ -mxGraphView.prototype.getStates = function() -{ - return this.states; -}; - -/** - * Function: setStates - * - * Sets <states>. - */ -mxGraphView.prototype.setStates = function(value) -{ - this.states = value; -}; - -/** - * Function: getCellStates - * - * Returns the <mxCellStates> for the given array of <mxCells>. The array - * contains all states that are not null, that is, the returned array may - * have less elements than the given array. If no argument is given, then - * this returns <states>. - */ -mxGraphView.prototype.getCellStates = function(cells) -{ - if (cells == null) - { - return this.states; - } - else - { - var result = []; - - for (var i = 0; i < cells.length; i++) - { - var state = this.getState(cells[i]); - - if (state != null) - { - result.push(state); - } - } - - return result; - } -}; - -/** - * Function: removeState - * - * Removes and returns the <mxCellState> for the given cell. - * - * Parameters: - * - * cell - <mxCell> for which the <mxCellState> should be removed. - */ -mxGraphView.prototype.removeState = function(cell) -{ - var state = null; - - if (cell != null) - { - state = this.states.remove(cell); - - if (state != null) - { - this.graph.cellRenderer.destroy(state); - state.destroy(); - } - } - - return state; -}; - -/** - * Function: createState - * - * Creates and returns an <mxCellState> for the given cell and initializes - * it using <mxCellRenderer.initialize>. - * - * Parameters: - * - * cell - <mxCell> for which a new <mxCellState> should be created. - */ -mxGraphView.prototype.createState = function(cell) -{ - var style = this.graph.getCellStyle(cell); - var state = new mxCellState(this, cell, style); - this.graph.cellRenderer.initialize(state, this.isRendering()); - - return state; -}; - -/** - * Function: getCanvas - * - * Returns the DOM node that contains the background-, draw- and - * overlaypane. - */ -mxGraphView.prototype.getCanvas = function() -{ - return this.canvas; -}; - -/** - * Function: getBackgroundPane - * - * Returns the DOM node that represents the background layer. - */ -mxGraphView.prototype.getBackgroundPane = function() -{ - return this.backgroundPane; -}; - -/** - * Function: getDrawPane - * - * Returns the DOM node that represents the main drawing layer. - */ -mxGraphView.prototype.getDrawPane = function() -{ - return this.drawPane; -}; - -/** - * Function: getOverlayPane - * - * Returns the DOM node that represents the topmost drawing layer. - */ -mxGraphView.prototype.getOverlayPane = function() -{ - return this.overlayPane; -}; - -/** - * Function: isContainerEvent - * - * Returns true if the event origin is one of the drawing panes or - * containers of the view. - */ -mxGraphView.prototype.isContainerEvent = function(evt) -{ - var source = mxEvent.getSource(evt); - - return (source == this.graph.container || - source.parentNode == this.backgroundPane || - (source.parentNode != null && - source.parentNode.parentNode == this.backgroundPane) || - source == this.canvas.parentNode || - source == this.canvas || - source == this.backgroundPane || - source == this.drawPane || - source == this.overlayPane); -}; - -/** - * Function: isScrollEvent - * - * Returns true if the event origin is one of the scrollbars of the - * container in IE. Such events are ignored. - */ - mxGraphView.prototype.isScrollEvent = function(evt) -{ - var offset = mxUtils.getOffset(this.graph.container); - var pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y); - - var outWidth = this.graph.container.offsetWidth; - var inWidth = this.graph.container.clientWidth; - - if (outWidth > inWidth && pt.x > inWidth + 2 && pt.x <= outWidth) - { - return true; - } - - var outHeight = this.graph.container.offsetHeight; - var inHeight = this.graph.container.clientHeight; - - if (outHeight > inHeight && pt.y > inHeight + 2 && pt.y <= outHeight) - { - return true; - } - - return false; -}; - -/** - * Function: init - * - * Initializes the graph event dispatch loop for the specified container - * and invokes <create> to create the required DOM nodes for the display. - */ -mxGraphView.prototype.init = function() -{ - this.installListeners(); - - // Creates the DOM nodes for the respective display dialect - var graph = this.graph; - - if (graph.dialect == mxConstants.DIALECT_SVG) - { - this.createSvg(); - } - else if (graph.dialect == mxConstants.DIALECT_VML) - { - this.createVml(); - } - else - { - this.createHtml(); - } -}; - -/** - * Function: installListeners - * - * Installs the required listeners in the container. - */ -mxGraphView.prototype.installListeners = function() -{ - var graph = this.graph; - var container = graph.container; - - if (container != null) - { - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Adds basic listeners for graph event dispatching - mxEvent.addListener(container, md, - mxUtils.bind(this, function(evt) - { - // Workaround for touch-based device not transferring - // the focus while editing with virtual keyboard - if (mxClient.IS_TOUCH && graph.isEditing()) - { - graph.stopEditing(!graph.isInvokesStopCellEditing()); - } - - // Condition to avoid scrollbar events starting a rubberband - // selection - if (this.isContainerEvent(evt) && ((!mxClient.IS_IE && - !mxClient.IS_GC && !mxClient.IS_OP && !mxClient.IS_SF) || - !this.isScrollEvent(evt))) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(container, mm, - mxUtils.bind(this, function(evt) - { - if (this.isContainerEvent(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(container, mu, - mxUtils.bind(this, function(evt) - { - if (this.isContainerEvent(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - } - }) - ); - - // Adds listener for double click handling on background - mxEvent.addListener(container, 'dblclick', - mxUtils.bind(this, function(evt) - { - graph.dblClick(evt); - }) - ); - - // Workaround for touch events which started on some DOM node - // on top of the container, in which case the cells under the - // mouse for the move and up events are not detected. - var getState = function(evt) - { - var state = null; - - // Workaround for touch events which started on some DOM node - // on top of the container, in which case the cells under the - // mouse for the move and up events are not detected. - if (mxClient.IS_TOUCH) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(container, x, y); - state = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return state; - }; - - // Adds basic listeners for graph event dispatching outside of the - // container and finishing the handling of a single gesture - // Implemented via graph event dispatch loop to avoid duplicate events - // in Firefox and Chrome - graph.addMouseListener( - { - mouseDown: function(sender, me) - { - graph.panningHandler.hideMenu(); - }, - mouseMove: function() { }, - mouseUp: function() { } - }); - mxEvent.addListener(document, mm, - mxUtils.bind(this, function(evt) - { - // Hides the tooltip if mouse is outside container - if (graph.tooltipHandler != null && - graph.tooltipHandler.isHideOnHover()) - { - graph.tooltipHandler.hide(); - } - - if (this.captureDocumentGesture && graph.isMouseDown && - !mxEvent.isConsumed(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, getState(evt))); - } - }) - ); - mxEvent.addListener(document, mu, - mxUtils.bind(this, function(evt) - { - if (this.captureDocumentGesture) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - } - }) - ); - } -}; - -/** - * Function: create - * - * Creates the DOM nodes for the HTML display. - */ -mxGraphView.prototype.createHtml = function() -{ - var container = this.graph.container; - - if (container != null) - { - this.canvas = this.createHtmlPane('100%', '100%'); - - // Uses minimal size for inner DIVs on Canvas. This is required - // for correct event processing in IE. If we have an overlapping - // DIV then the events on the cells are only fired for labels. - this.backgroundPane = this.createHtmlPane('1px', '1px'); - this.drawPane = this.createHtmlPane('1px', '1px'); - this.overlayPane = this.createHtmlPane('1px', '1px'); - - this.canvas.appendChild(this.backgroundPane); - this.canvas.appendChild(this.drawPane); - this.canvas.appendChild(this.overlayPane); - - container.appendChild(this.canvas); - - // Implements minWidth/minHeight in quirks mode - if (mxClient.IS_QUIRKS) - { - var onResize = mxUtils.bind(this, function(evt) - { - var bounds = this.getGraphBounds(); - var width = bounds.x + bounds.width + this.graph.border; - var height = bounds.y + bounds.height + this.graph.border; - - this.updateHtmlCanvasSize(width, height); - }); - - mxEvent.addListener(window, 'resize', onResize); - } - } -}; - -/** - * Function: updateHtmlCanvasSize - * - * Updates the size of the HTML canvas. - */ -mxGraphView.prototype.updateHtmlCanvasSize = function(width, height) -{ - if (this.graph.container != null) - { - var ow = this.graph.container.offsetWidth; - var oh = this.graph.container.offsetHeight; - - if (ow < width) - { - this.canvas.style.width = width + 'px'; - } - else - { - this.canvas.style.width = '100%'; - } - - if (oh < height) - { - this.canvas.style.height = height + 'px'; - } - else - { - this.canvas.style.height = '100%'; - } - } -}; - -/** - * Function: createHtmlPane - * - * Creates and returns a drawing pane in HTML (DIV). - */ -mxGraphView.prototype.createHtmlPane = function(width, height) -{ - var pane = document.createElement('DIV'); - - if (width != null && height != null) - { - pane.style.position = 'absolute'; - pane.style.left = '0px'; - pane.style.top = '0px'; - - pane.style.width = width; - pane.style.height = height; - } - else - { - pane.style.position = 'relative'; - } - - return pane; -}; - -/** - * Function: create - * - * Creates the DOM nodes for the VML display. - */ -mxGraphView.prototype.createVml = function() -{ - var container = this.graph.container; - - if (container != null) - { - var width = container.offsetWidth; - var height = container.offsetHeight; - this.canvas = this.createVmlPane(width, height); - - this.backgroundPane = this.createVmlPane(width, height); - this.drawPane = this.createVmlPane(width, height); - this.overlayPane = this.createVmlPane(width, height); - - this.canvas.appendChild(this.backgroundPane); - this.canvas.appendChild(this.drawPane); - this.canvas.appendChild(this.overlayPane); - - container.appendChild(this.canvas); - } -}; - -/** - * Function: createVmlPane - * - * Creates a drawing pane in VML (group). - */ -mxGraphView.prototype.createVmlPane = function(width, height) -{ - var pane = document.createElement('v:group'); - - // At this point the width and height are potentially - // uninitialized. That's OK. - pane.style.position = 'absolute'; - pane.style.left = '0px'; - pane.style.top = '0px'; - - pane.style.width = width+'px'; - pane.style.height = height+'px'; - - pane.setAttribute('coordsize', width+','+height); - pane.setAttribute('coordorigin', '0,0'); - - return pane; -}; - -/** - * Function: create - * - * Creates and returns the DOM nodes for the SVG display. - */ -mxGraphView.prototype.createSvg = function() -{ - var container = this.graph.container; - this.canvas = document.createElementNS(mxConstants.NS_SVG, 'g'); - - // For background image - this.backgroundPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.backgroundPane); - - // Adds two layers (background is early feature) - this.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.drawPane); - - this.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.overlayPane); - - var root = document.createElementNS(mxConstants.NS_SVG, 'svg'); - root.style.width = '100%'; - root.style.height = '100%'; - - if (mxClient.IS_IE) - { - root.style.marginBottom = '-4px'; - } - - root.appendChild(this.canvas); - - if (container != null) - { - container.appendChild(root); - - // Workaround for offset of container - var style = mxUtils.getCurrentStyle(container); - - if (style.position == 'static') - { - container.style.position = 'relative'; - } - } -}; - -/** - * Function: destroy - * - * Destroys the view and all its resources. - */ -mxGraphView.prototype.destroy = function() -{ - var root = (this.canvas != null) ? this.canvas.ownerSVGElement : null; - - if (root == null) - { - root = this.canvas; - } - - if (root != null && root.parentNode != null) - { - this.clear(this.currentRoot, true); - mxEvent.removeAllListeners(document); - mxEvent.release(this.graph.container); - root.parentNode.removeChild(root); - - this.canvas = null; - this.backgroundPane = null; - this.drawPane = null; - this.overlayPane = null; - } -}; - -/** - * Class: mxCurrentRootChange - * - * Action to change the current root in a view. - * - * Constructor: mxCurrentRootChange - * - * Constructs a change of the current root in the given view. - */ -function mxCurrentRootChange(view, root) -{ - this.view = view; - this.root = root; - this.previous = root; - this.isUp = root == null; - - if (!this.isUp) - { - var tmp = this.view.currentRoot; - var model = this.view.graph.getModel(); - - while (tmp != null) - { - if (tmp == root) - { - this.isUp = true; - break; - } - - tmp = model.getParent(tmp); - } - } -}; - -/** - * Function: execute - * - * Changes the current root of the view. - */ -mxCurrentRootChange.prototype.execute = function() -{ - var tmp = this.view.currentRoot; - this.view.currentRoot = this.previous; - this.previous = tmp; - - var translate = this.view.graph.getTranslateForRoot(this.view.currentRoot); - - if (translate != null) - { - this.view.translate = new mxPoint(-translate.x, -translate.y); - } - - var name = (this.isUp) ? mxEvent.UP : mxEvent.DOWN; - this.view.fireEvent(new mxEventObject(name, - 'root', this.view.currentRoot, 'previous', this.previous)); - - if (this.isUp) - { - this.view.clear(this.view.currentRoot, true); - this.view.validate(); - } - else - { - this.view.refresh(); - } - - this.isUp = !this.isUp; -}; diff --git a/src/js/view/mxLayoutManager.js b/src/js/view/mxLayoutManager.js deleted file mode 100644 index ee8ec65..0000000 --- a/src/js/view/mxLayoutManager.js +++ /dev/null @@ -1,375 +0,0 @@ -/** - * $Id: mxLayoutManager.js,v 1.21 2012-01-04 10:01:16 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxLayoutManager - * - * Implements a layout manager that updates the layout for a given transaction. - * - * Example: - * - * (code) - * var layoutMgr = new mxLayoutManager(graph); - * layoutMgr.getLayout = function(cell) - * { - * return layout; - * }; - * (end) - * - * Event: mxEvent.LAYOUT_CELLS - * - * Fires between begin- and endUpdate after all cells have been layouted in - * <layoutCells>. The <code>cells</code> property contains all cells that have - * been passed to <layoutCells>. - * - * Constructor: mxLayoutManager - * - * Constructs a new automatic layout for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxLayoutManager(graph) -{ - // Executes the layout before the changes are dispatched - this.undoHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.beforeUndo(evt.getProperty('edit')); - } - }); - - // Notifies the layout of a move operation inside a parent - this.moveHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event')); - } - }); - - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxLayoutManager.prototype = new mxEventSource(); -mxLayoutManager.prototype.constructor = mxLayoutManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxLayoutManager.prototype.graph = null; - -/** - * Variable: bubbling - * - * Specifies if the layout should bubble along - * the cell hierarchy. Default is true. - */ -mxLayoutManager.prototype.bubbling = true; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxLayoutManager.prototype.enabled = true; - -/** - * Variable: updateHandler - * - * Holds the function that handles the endUpdate event. - */ -mxLayoutManager.prototype.updateHandler = null; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxLayoutManager.prototype.moveHandler = null; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxLayoutManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxLayoutManager.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isBubbling - * - * Returns true if a layout should bubble, that is, if the parent layout - * should be executed whenever a cell layout (layout of the children of - * a cell) has been executed. This implementation returns <bubbling>. - */ -mxLayoutManager.prototype.isBubbling = function() -{ - return this.bubbling; -}; - -/** - * Function: setBubbling - * - * Sets <bubbling>. - */ -mxLayoutManager.prototype.setBubbling = function(value) -{ - this.bubbling = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this layout operates on. - */ -mxLayoutManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the layouts operate on. - */ -mxLayoutManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - var model = this.graph.getModel(); - model.removeListener(this.undoHandler); - this.graph.removeListener(this.moveHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - var model = this.graph.getModel(); - model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler); - this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler); - } -}; - -/** - * Function: getLayout - * - * Returns the layout to be executed for the given graph and parent. - */ -mxLayoutManager.prototype.getLayout = function(parent) -{ - return null; -}; - -/** - * Function: beforeUndo - * - * Called from the undoHandler. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxLayoutManager.prototype.beforeUndo = function(undoableEdit) -{ - var cells = this.getCellsForChanges(undoableEdit.changes); - var model = this.getGraph().getModel(); - - // Adds all parent ancestors - if (this.isBubbling()) - { - var tmp = model.getParents(cells); - - while (tmp.length > 0) - { - cells = cells.concat(tmp); - tmp = model.getParents(tmp); - } - } - - this.layoutCells(mxUtils.sortCells(cells, false)); -}; - -/** - * Function: cellsMoved - * - * Called from the moveHandler. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxLayoutManager.prototype.cellsMoved = function(cells, evt) -{ - if (cells != null && - evt != null) - { - var point = mxUtils.convertPoint(this.getGraph().container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - var model = this.getGraph().getModel(); - - // Checks if a layout exists to take care of the moving - for (var i = 0; i < cells.length; i++) - { - var layout = this.getLayout(model.getParent(cells[i])); - - if (layout != null) - { - layout.moveCell(cells[i], point.x, point.y); - } - } - } -}; - -/** - * Function: getCellsForEdit - * - * Returns the cells to be layouted for the given sequence of changes. - */ -mxLayoutManager.prototype.getCellsForChanges = function(changes) -{ - var result = []; - var hash = new Object(); - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change instanceof mxRootChange) - { - return []; - } - else - { - var cells = this.getCellsForChange(change); - - for (var j = 0; j < cells.length; j++) - { - if (cells[j] != null) - { - var id = mxCellPath.create(cells[j]); - - if (hash[id] == null) - { - hash[id] = cells[j]; - result.push(cells[j]); - } - } - } - } - } - - return result; -}; - -/** - * Function: getCellsForChange - * - * Executes all layouts which have been scheduled during the - * changes. - */ -mxLayoutManager.prototype.getCellsForChange = function(change) -{ - var model = this.getGraph().getModel(); - - if (change instanceof mxChildChange) - { - return [change.child, change.previous, model.getParent(change.child)]; - } - else if (change instanceof mxTerminalChange || - change instanceof mxGeometryChange) - { - return [change.cell, model.getParent(change.cell)]; - } - - return []; -}; - -/** - * Function: layoutCells - * - * Executes all layouts which have been scheduled during the - * changes. - */ -mxLayoutManager.prototype.layoutCells = function(cells) -{ - if (cells.length > 0) - { - // Invokes the layouts while removing duplicates - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - var last = null; - - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != model.getRoot() && - cells[i] != last) - { - last = cells[i]; - this.executeLayout(this.getLayout(last), last); - } - } - - this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells)); - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: executeLayout - * - * Executes the given layout on the given parent. - */ -mxLayoutManager.prototype.executeLayout = function(layout, parent) -{ - if (layout != null && parent != null) - { - layout.execute(parent); - } -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxLayoutManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxMultiplicity.js b/src/js/view/mxMultiplicity.js deleted file mode 100644 index c927d3f..0000000 --- a/src/js/view/mxMultiplicity.js +++ /dev/null @@ -1,257 +0,0 @@ -/** - * $Id: mxMultiplicity.js,v 1.24 2010-11-03 14:52:40 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxMultiplicity - * - * Defines invalid connections along with the error messages that they produce. - * To add or remove rules on a graph, you must add/remove instances of this - * class to <mxGraph.multiplicities>. - * - * Example: - * - * (code) - * graph.multiplicities.push(new mxMultiplicity( - * true, 'rectangle', null, null, 0, 2, ['circle'], - * 'Only 2 targets allowed', - * 'Only circle targets allowed')); - * (end) - * - * Defines a rule where each rectangle must be connected to no more than 2 - * circles and no other types of targets are allowed. - * - * Constructor: mxMultiplicity - * - * Instantiate class mxMultiplicity in order to describe allowed - * connections in a graph. Not all constraints can be enforced while - * editing, some must be checked at validation time. The <countError> and - * <typeError> are treated as resource keys in <mxResources>. - * - * Parameters: - * - * source - Boolean indicating if this rule applies to the source or target - * terminal. - * type - Type of the source or target terminal that this rule applies to. - * See <type> for more information. - * attr - Optional attribute name to match the source or target terminal. - * value - Optional attribute value to match the source or target terminal. - * min - Minimum number of edges for this rule. Default is 1. - * max - Maximum number of edges for this rule. n means infinite. Default - * is n. - * validNeighbors - Array of types of the opposite terminal for which this - * rule applies. - * countError - Error to be displayed for invalid number of edges. - * typeError - Error to be displayed for invalid opposite terminals. - * validNeighborsAllowed - Optional boolean indicating if the array of - * opposite types should be valid or invalid. - */ -function mxMultiplicity(source, type, attr, value, min, max, - validNeighbors, countError, typeError, validNeighborsAllowed) -{ - this.source = source; - this.type = type; - this.attr = attr; - this.value = value; - this.min = (min != null) ? min : 0; - this.max = (max != null) ? max : 'n'; - this.validNeighbors = validNeighbors; - this.countError = mxResources.get(countError) || countError; - this.typeError = mxResources.get(typeError) || typeError; - this.validNeighborsAllowed = (validNeighborsAllowed != null) ? - validNeighborsAllowed : true; -}; - -/** - * Variable: type - * - * Defines the type of the source or target terminal. The type is a string - * passed to <mxUtils.isNode> together with the source or target vertex - * value as the first argument. - */ -mxMultiplicity.prototype.type = null; - -/** - * Variable: attr - * - * Optional string that specifies the attributename to be passed to - * <mxUtils.isNode> to check if the rule applies to a cell. - */ -mxMultiplicity.prototype.attr = null; - -/** - * Variable: value - * - * Optional string that specifies the value of the attribute to be passed - * to <mxUtils.isNode> to check if the rule applies to a cell. - */ -mxMultiplicity.prototype.value = null; - -/** - * Variable: source - * - * Boolean that specifies if the rule is applied to the source or target - * terminal of an edge. - */ -mxMultiplicity.prototype.source = null; - -/** - * Variable: min - * - * Defines the minimum number of connections for which this rule applies. - * Default is 0. - */ -mxMultiplicity.prototype.min = null; - -/** - * Variable: max - * - * Defines the maximum number of connections for which this rule applies. - * A value of 'n' means unlimited times. Default is 'n'. - */ -mxMultiplicity.prototype.max = null; - -/** - * Variable: validNeighbors - * - * Holds an array of strings that specify the type of neighbor for which - * this rule applies. The strings are used in <mxCell.is> on the opposite - * terminal to check if the rule applies to the connection. - */ -mxMultiplicity.prototype.validNeighbors = null; - -/** - * Variable: validNeighborsAllowed - * - * Boolean indicating if the list of validNeighbors are those that are allowed - * for this rule or those that are not allowed for this rule. - */ -mxMultiplicity.prototype.validNeighborsAllowed = true; - -/** - * Variable: countError - * - * Holds the localized error message to be displayed if the number of - * connections for which the rule applies is smaller than <min> or greater - * than <max>. - */ -mxMultiplicity.prototype.countError = null; - -/** - * Variable: typeError - * - * Holds the localized error message to be displayed if the type of the - * neighbor for a connection does not match the rule. - */ -mxMultiplicity.prototype.typeError = null; - -/** - * Function: check - * - * Checks the multiplicity for the given arguments and returns the error - * for the given connection or null if the multiplicity does not apply. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph> instance. - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - * sourceOut - Number of outgoing edges from the source terminal. - * targetIn - Number of incoming edges for the target terminal. - */ -mxMultiplicity.prototype.check = function(graph, edge, source, target, sourceOut, targetIn) -{ - var error = ''; - - if ((this.source && this.checkTerminal(graph, source, edge)) || - (!this.source && this.checkTerminal(graph, target, edge))) - { - if (this.countError != null && - ((this.source && (this.max == 0 || (sourceOut >= this.max))) || - (!this.source && (this.max == 0 || (targetIn >= this.max))))) - { - error += this.countError + '\n'; - } - - if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0) - { - var isValid = this.checkNeighbors(graph, edge, source, target); - - if (!isValid) - { - error += this.typeError + '\n'; - } - } - } - - return (error.length > 0) ? error : null; -}; - -/** - * Function: checkNeighbors - * - * Checks if there are any valid neighbours in <validNeighbors>. This is only - * called if <validNeighbors> is a non-empty array. - */ -mxMultiplicity.prototype.checkNeighbors = function(graph, edge, source, target) -{ - var sourceValue = graph.model.getValue(source); - var targetValue = graph.model.getValue(target); - var isValid = !this.validNeighborsAllowed; - var valid = this.validNeighbors; - - for (var j = 0; j < valid.length; j++) - { - if (this.source && - this.checkType(graph, targetValue, valid[j])) - { - isValid = this.validNeighborsAllowed; - break; - } - else if (!this.source && - this.checkType(graph, sourceValue, valid[j])) - { - isValid = this.validNeighborsAllowed; - break; - } - } - - return isValid; -}; - -/** - * Function: checkTerminal - * - * Checks the given terminal cell and returns true if this rule applies. The - * given cell is the source or target of the given edge, depending on - * <source>. This implementation uses <checkType> on the terminal's value. - */ -mxMultiplicity.prototype.checkTerminal = function(graph, terminal, edge) -{ - var value = graph.model.getValue(terminal); - - return this.checkType(graph, value, this.type, this.attr, this.value); -}; - -/** - * Function: checkType - * - * Checks the type of the given value. - */ -mxMultiplicity.prototype.checkType = function(graph, value, type, attr, attrValue) -{ - if (value != null) - { - if (!isNaN(value.nodeType)) // Checks if value is a DOM node - { - return mxUtils.isNode(value, type, attr, attrValue); - } - else - { - return value == type; - } - } - - return false; -}; diff --git a/src/js/view/mxOutline.js b/src/js/view/mxOutline.js deleted file mode 100644 index a0d6fd3..0000000 --- a/src/js/view/mxOutline.js +++ /dev/null @@ -1,649 +0,0 @@ -/** - * $Id: mxOutline.js,v 1.81 2012-06-20 14:13:37 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxOutline - * - * Implements an outline (aka overview) for a graph. Set <updateOnPan> to true - * to enable updates while the source graph is panning. - * - * Example: - * - * (code) - * var outline = new mxOutline(graph, div); - * (end) - * - * If the selection border in the outline appears behind the contents of the - * graph, then you can use the following code. (This may happen when using a - * transparent container for the outline in IE.) - * - * (code) - * mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_EXACT; - * (end) - * - * To move the graph to the top, left corner the following code can be used. - * - * (code) - * var scale = graph.view.scale; - * var bounds = graph.getGraphBounds(); - * graph.view.setTranslate(-bounds.x / scale, -bounds.y / scale); - * (end) - * - * To toggle the suspended mode, the following can be used. - * - * (code) - * outline.suspended = !outln.suspended; - * if (!outline.suspended) - * { - * outline.update(true); - * } - * (end) - * - * Constructor: mxOutline - * - * Constructs a new outline for the specified graph inside the given - * container. - * - * Parameters: - * - * source - <mxGraph> to create the outline for. - * container - DOM node that will contain the outline. - */ -function mxOutline(source, container) -{ - this.source = source; - - if (container != null) - { - this.init(container); - } -}; - -/** - * Function: source - * - * Reference to the source <mxGraph>. - */ -mxOutline.prototype.source = null; - -/** - * Function: outline - * - * Reference to the outline <mxGraph>. - */ -mxOutline.prototype.outline = null; - -/** - * Function: graphRenderHint - * - * Renderhint to be used for the outline graph. Default is faster. - */ -mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_FASTER; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxOutline.prototype.enabled = true; - -/** - * Variable: showViewport - * - * Specifies a viewport rectangle should be shown. Default is true. - */ -mxOutline.prototype.showViewport = true; - -/** - * Variable: border - * - * Border to be added at the bottom and right. Default is 10. - */ -mxOutline.prototype.border = 10; - -/** - * Variable: enabled - * - * Specifies the size of the sizer handler. Default is 8. - */ -mxOutline.prototype.sizerSize = 8; - -/** - * Variable: updateOnPan - * - * Specifies if <update> should be called for <mxEvent.PAN> in the source - * graph. Default is false. - */ -mxOutline.prototype.updateOnPan = false; - -/** - * Variable: sizerImage - * - * Optional <mxImage> to be used for the sizer. Default is null. - */ -mxOutline.prototype.sizerImage = null; - -/** - * Variable: suspended - * - * Optional boolean flag to suspend updates. Default is false. This flag will - * also suspend repaints of the outline. To toggle this switch, use the - * following code. - * - * (code) - * nav.suspended = !nav.suspended; - * - * if (!nav.suspended) - * { - * nav.update(true); - * } - * (end) - */ -mxOutline.prototype.suspended = false; - -/** - * Function: init - * - * Initializes the outline inside the given container. - */ -mxOutline.prototype.init = function(container) -{ - this.outline = new mxGraph(container, this.source.getModel(), this.graphRenderHint, this.source.getStylesheet()); - this.outline.foldingEnabled = false; - this.outline.autoScroll = false; - - // Do not repaint when suspended - var outlineGraphModelChanged = this.outline.graphModelChanged; - this.outline.graphModelChanged = mxUtils.bind(this, function(changes) - { - if (!this.suspended && this.outline != null) - { - outlineGraphModelChanged.apply(this.outline, arguments); - } - }); - - // Enables faster painting in SVG - if (mxClient.IS_SVG) - { - var node = this.outline.getView().getCanvas().parentNode; - node.setAttribute('shape-rendering', 'optimizeSpeed'); - node.setAttribute('image-rendering', 'optimizeSpeed'); - } - - // Hides cursors and labels - this.outline.labelsVisible = false; - this.outline.setEnabled(false); - - this.updateHandler = mxUtils.bind(this, function(sender, evt) - { - if (!this.suspended && !this.active) - { - this.update(); - } - }); - - // Updates the scale of the outline after a change of the main graph - this.source.getModel().addListener(mxEvent.CHANGE, this.updateHandler); - this.outline.addMouseListener(this); - - // Adds listeners to keep the outline in sync with the source graph - var view = this.source.getView(); - view.addListener(mxEvent.SCALE, this.updateHandler); - view.addListener(mxEvent.TRANSLATE, this.updateHandler); - view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.updateHandler); - view.addListener(mxEvent.DOWN, this.updateHandler); - view.addListener(mxEvent.UP, this.updateHandler); - - // Updates blue rectangle on scroll - mxEvent.addListener(this.source.container, 'scroll', this.updateHandler); - - this.panHandler = mxUtils.bind(this, function(sender) - { - if (this.updateOnPan) - { - this.updateHandler.apply(this, arguments); - } - }); - this.source.addListener(mxEvent.PAN, this.panHandler); - - // Refreshes the graph in the outline after a refresh of the main graph - this.refreshHandler = mxUtils.bind(this, function(sender) - { - this.outline.setStylesheet(this.source.getStylesheet()); - this.outline.refresh(); - }); - this.source.addListener(mxEvent.REFRESH, this.refreshHandler); - - // Creates the blue rectangle for the viewport - this.bounds = new mxRectangle(0, 0, 0, 0); - this.selectionBorder = new mxRectangleShape(this.bounds, null, - mxConstants.OUTLINE_COLOR, mxConstants.OUTLINE_STROKEWIDTH); - this.selectionBorder.dialect = - (this.outline.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.selectionBorder.crisp = true; - this.selectionBorder.init(this.outline.getView().getOverlayPane()); - mxEvent.redirectMouseEvents(this.selectionBorder.node, this.outline); - this.selectionBorder.node.style.background = ''; - - // Creates a small blue rectangle for sizing (sizer handle) - this.sizer = this.createSizer(); - this.sizer.init(this.outline.getView().getOverlayPane()); - - if (this.enabled) - { - this.sizer.node.style.cursor = 'pointer'; - } - - // Redirects all events from the sizerhandle to the outline - mxEvent.addListener(this.sizer.node, (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown', - mxUtils.bind(this, function(evt) - { - this.outline.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt)); - }) - ); - - this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none'; - this.sizer.node.style.display = this.selectionBorder.node.style.display; - this.selectionBorder.node.style.cursor = 'move'; - - this.update(false); -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxOutline.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * value - Boolean that specifies the new enabled state. - */ -mxOutline.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: setZoomEnabled - * - * Enables or disables the zoom handling by showing or hiding the respective - * handle. - * - * Parameters: - * - * value - Boolean that specifies the new enabled state. - */ -mxOutline.prototype.setZoomEnabled = function(value) -{ - this.sizer.node.style.visibility = (value) ? 'visible' : 'hidden'; -}; - -/** - * Function: refresh - * - * Invokes <update> and revalidate the outline. This method is deprecated. - */ -mxOutline.prototype.refresh = function() -{ - this.update(true); -}; - -/** - * Function: createSizer - * - * Creates the shape used as the sizer. - */ -mxOutline.prototype.createSizer = function() -{ - if (this.sizerImage != null) - { - var sizer = new mxImageShape(new mxRectangle(0, 0, this.sizerImage.width, this.sizerImage.height), this.sizerImage.src); - sizer.dialect = this.outline.dialect; - - return sizer; - } - else - { - var sizer = new mxRectangleShape(new mxRectangle(0, 0, this.sizerSize, this.sizerSize), - mxConstants.OUTLINE_HANDLE_FILLCOLOR, mxConstants.OUTLINE_HANDLE_STROKECOLOR); - sizer.dialect = this.outline.dialect; - sizer.crisp = true; - - return sizer; - } -}; - -/** - * Function: getSourceContainerSize - * - * Returns the size of the source container. - */ -mxOutline.prototype.getSourceContainerSize = function() -{ - return new mxRectangle(0, 0, this.source.container.scrollWidth, this.source.container.scrollHeight); -}; - -/** - * Function: getOutlineOffset - * - * Returns the offset for drawing the outline graph. - */ -mxOutline.prototype.getOutlineOffset = function(scale) -{ - return null; -}; - -/** - * Function: update - * - * Updates the outline. - */ -mxOutline.prototype.update = function(revalidate) -{ - if (this.source != null) - { - var sourceScale = this.source.view.scale; - var scaledGraphBounds = this.source.getGraphBounds(); - var unscaledGraphBounds = new mxRectangle(scaledGraphBounds.x / sourceScale + this.source.panDx, - scaledGraphBounds.y / sourceScale + this.source.panDy, scaledGraphBounds.width / sourceScale, - scaledGraphBounds.height / sourceScale); - - var unscaledFinderBounds = new mxRectangle(0, 0, - this.source.container.clientWidth / sourceScale, - this.source.container.clientHeight / sourceScale); - - var union = unscaledGraphBounds.clone(); - union.add(unscaledFinderBounds); - - // Zooms to the scrollable area if that is bigger than the graph - var size = this.getSourceContainerSize(); - var completeWidth = Math.max(size.width / sourceScale, union.width); - var completeHeight = Math.max(size.height / sourceScale, union.height); - - var availableWidth = Math.max(0, this.outline.container.clientWidth - this.border); - var availableHeight = Math.max(0, this.outline.container.clientHeight - this.border); - - var outlineScale = Math.min(availableWidth / completeWidth, availableHeight / completeHeight); - var scale = outlineScale; - - if (scale > 0) - { - if (this.outline.getView().scale != scale) - { - this.outline.getView().scale = scale; - revalidate = true; - } - - var navView = this.outline.getView(); - - if (navView.currentRoot != this.source.getView().currentRoot) - { - navView.setCurrentRoot(this.source.getView().currentRoot); - } - - var t = this.source.view.translate; - var tx = t.x + this.source.panDx; - var ty = t.y + this.source.panDy; - - var off = this.getOutlineOffset(scale); - - if (off != null) - { - tx += off.x; - ty += off.y; - } - - if (unscaledGraphBounds.x < 0) - { - tx = tx - unscaledGraphBounds.x; - } - if (unscaledGraphBounds.y < 0) - { - ty = ty - unscaledGraphBounds.y; - } - - if (navView.translate.x != tx || navView.translate.y != ty) - { - navView.translate.x = tx; - navView.translate.y = ty; - revalidate = true; - } - - // Prepares local variables for computations - var t2 = navView.translate; - scale = this.source.getView().scale; - var scale2 = scale / navView.scale; - var scale3 = 1.0 / navView.scale; - var container = this.source.container; - - // Updates the bounds of the viewrect in the navigation - this.bounds = new mxRectangle( - (t2.x - t.x - this.source.panDx) / scale3, - (t2.y - t.y - this.source.panDy) / scale3, - (container.clientWidth / scale2), - (container.clientHeight / scale2)); - - // Adds the scrollbar offset to the finder - this.bounds.x += this.source.container.scrollLeft * navView.scale / scale; - this.bounds.y += this.source.container.scrollTop * navView.scale / scale; - - var b = this.selectionBorder.bounds; - - if (b.x != this.bounds.x || b.y != this.bounds.y || b.width != this.bounds.width || b.height != this.bounds.height) - { - this.selectionBorder.bounds = this.bounds; - this.selectionBorder.redraw(); - } - - // Updates the bounds of the zoom handle at the bottom right - var b = this.sizer.bounds; - var b2 = new mxRectangle(this.bounds.x + this.bounds.width - b.width / 2, - this.bounds.y + this.bounds.height - b.height / 2, b.width, b.height); - - if (b.x != b2.x || b.y != b2.y || b.width != b2.width || b.height != b2.height) - { - this.sizer.bounds = b2; - - // Avoids update of visibility in redraw for VML - if (this.sizer.node.style.visibility != 'hidden') - { - this.sizer.redraw(); - } - } - - if (revalidate) - { - this.outline.view.revalidate(); - } - } - } -}; - -/** - * Function: mouseDown - * - * Handles the event by starting a translation or zoom. - */ -mxOutline.prototype.mouseDown = function(sender, me) -{ - if (this.enabled && this.showViewport) - { - this.zoom = me.isSource(this.sizer); - this.startX = me.getX(); - this.startY = me.getY(); - this.active = true; - - if (this.source.useScrollbarsForPanning && - mxUtils.hasScrollbars(this.source.container)) - { - this.dx0 = this.source.container.scrollLeft; - this.dy0 = this.source.container.scrollTop; - } - else - { - this.dx0 = 0; - this.dy0 = 0; - } - } - - me.consume(); -}; - -/** - * Function: mouseMove - * - * Handles the event by previewing the viewrect in <graph> and updating the - * rectangle that represents the viewrect in the outline. - */ -mxOutline.prototype.mouseMove = function(sender, me) -{ - if (this.active) - { - this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none'; - this.sizer.node.style.display = this.selectionBorder.node.style.display; - - var dx = me.getX() - this.startX; - var dy = me.getY() - this.startY; - var bounds = null; - - if (!this.zoom) - { - // Previews the panning on the source graph - var scale = this.outline.getView().scale; - bounds = new mxRectangle(this.bounds.x + dx, - this.bounds.y + dy, this.bounds.width, this.bounds.height); - this.selectionBorder.bounds = bounds; - this.selectionBorder.redraw(); - dx /= scale; - dx *= this.source.getView().scale; - dy /= scale; - dy *= this.source.getView().scale; - this.source.panGraph(-dx - this.dx0, -dy - this.dy0); - } - else - { - // Does *not* preview zooming on the source graph - var container = this.source.container; - var viewRatio = container.clientWidth / container.clientHeight; - dy = dx / viewRatio; - bounds = new mxRectangle(this.bounds.x, - this.bounds.y, - Math.max(1, this.bounds.width + dx), - Math.max(1, this.bounds.height + dy)); - this.selectionBorder.bounds = bounds; - this.selectionBorder.redraw(); - } - - // Updates the zoom handle - var b = this.sizer.bounds; - this.sizer.bounds = new mxRectangle( - bounds.x + bounds.width - b.width / 2, - bounds.y + bounds.height - b.height / 2, - b.width, b.height); - - // Avoids update of visibility in redraw for VML - if (this.sizer.node.style.visibility != 'hidden') - { - this.sizer.redraw(); - } - - me.consume(); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by applying the translation or zoom to <graph>. - */ -mxOutline.prototype.mouseUp = function(sender, me) -{ - if (this.active) - { - var dx = me.getX() - this.startX; - var dy = me.getY() - this.startY; - - if (Math.abs(dx) > 0 || Math.abs(dy) > 0) - { - if (!this.zoom) - { - // Applies the new translation if the source - // has no scrollbars - if (!this.source.useScrollbarsForPanning || - !mxUtils.hasScrollbars(this.source.container)) - { - this.source.panGraph(0, 0); - dx /= this.outline.getView().scale; - dy /= this.outline.getView().scale; - var t = this.source.getView().translate; - this.source.getView().setTranslate(t.x - dx, t.y - dy); - } - } - else - { - // Applies the new zoom - var w = this.selectionBorder.bounds.width; - var scale = this.source.getView().scale; - this.source.zoomTo(scale - (dx * scale) / w, false); - } - - this.update(); - me.consume(); - } - - // Resets the state of the handler - this.index = null; - this.active = false; - } -}; - -/** - * Function: destroy - * - * Destroy this outline and removes all listeners from <source>. - */ -mxOutline.prototype.destroy = function() -{ - if (this.source != null) - { - this.source.removeListener(this.panHandler); - this.source.removeListener(this.refreshHandler); - this.source.getModel().removeListener(this.updateHandler); - this.source.getView().removeListener(this.updateHandler); - mxEvent.addListener(this.source.container, 'scroll', this.updateHandler); - this.source = null; - } - - if (this.outline != null) - { - this.outline.removeMouseListener(this); - this.outline.destroy(); - this.outline = null; - } - - if (this.selectionBorder != null) - { - this.selectionBorder.destroy(); - this.selectionBorder = null; - } - - if (this.sizer != null) - { - this.sizer.destroy(); - this.sizer = null; - } -}; diff --git a/src/js/view/mxPerimeter.js b/src/js/view/mxPerimeter.js deleted file mode 100644 index 7aaa187..0000000 --- a/src/js/view/mxPerimeter.js +++ /dev/null @@ -1,484 +0,0 @@ -/** - * $Id: mxPerimeter.js,v 1.28 2012-01-11 09:06:56 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxPerimeter = -{ - /** - * Class: mxPerimeter - * - * Provides various perimeter functions to be used in a style - * as the value of <mxConstants.STYLE_PERIMETER>. Perimeters for - * rectangle, circle, rhombus and triangle are available. - * - * Example: - * - * (code) - * <add as="perimeter">mxPerimeter.RightAngleRectanglePerimeter</add> - * (end) - * - * Or programmatically: - * - * (code) - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - * (end) - * - * When adding new perimeter functions, it is recommended to use the - * mxPerimeter-namespace as follows: - * - * (code) - * mxPerimeter.CustomPerimeter = function (bounds, vertex, next, orthogonal) - * { - * var x = 0; // Calculate x-coordinate - * var y = 0; // Calculate y-coordainte - * - * return new mxPoint(x, y); - * } - * (end) - * - * The new perimeter should then be registered in the <mxStyleRegistry> as follows: - * (code) - * mxStyleRegistry.putValue('customPerimeter', mxPerimeter.CustomPerimeter); - * (end) - * - * The custom perimeter above can now be used in a specific vertex as follows: - * - * (code) - * model.setStyle(vertex, 'perimeter=customPerimeter'); - * (end) - * - * Note that the key of the <mxStyleRegistry> entry for the function should - * be used in string values, unless <mxGraphView.allowEval> is true, in - * which case you can also use mxPerimeter.CustomPerimeter for the value in - * the cell style above. - * - * Or it can be used for all vertices in the graph as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.CustomPerimeter; - * (end) - * - * Note that the object can be used directly when programmatically setting - * the value, but the key in the <mxStyleRegistry> should be used when - * setting the value via a key, value pair in a cell style. - * - * The parameters are explained in <RectanglePerimeter>. - * - * Function: RectanglePerimeter - * - * Describes a rectangular perimeter for the given bounds. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the absolute bounds of the - * vertex. - * vertex - <mxCellState> that represents the vertex. - * next - <mxPoint> that represents the nearest neighbour point on the - * given edge. - * orthogonal - Boolean that specifies if the orthogonal projection onto - * the perimeter should be returned. If this is false then the intersection - * of the perimeter and the line between the next and the center point is - * returned. - */ - RectanglePerimeter: function (bounds, vertex, next, orthogonal) - { - var cx = bounds.getCenterX(); - var cy = bounds.getCenterY(); - var dx = next.x - cx; - var dy = next.y - cy; - var alpha = Math.atan2(dy, dx); - var p = new mxPoint(0, 0); - var pi = Math.PI; - var pi2 = Math.PI/2; - var beta = pi2 - alpha; - var t = Math.atan2(bounds.height, bounds.width); - - if (alpha < -pi + t || alpha > pi - t) - { - // Left edge - p.x = bounds.x; - p.y = cy - bounds.width * Math.tan(alpha) / 2; - } - else if (alpha < -t) - { - // Top Edge - p.y = bounds.y; - p.x = cx - bounds.height * Math.tan(beta) / 2; - } - else if (alpha < t) - { - // Right Edge - p.x = bounds.x + bounds.width; - p.y = cy + bounds.width * Math.tan(alpha) / 2; - } - else - { - // Bottom Edge - p.y = bounds.y + bounds.height; - p.x = cx + bounds.height * Math.tan(beta) / 2; - } - - if (orthogonal) - { - if (next.x >= bounds.x && - next.x <= bounds.x + bounds.width) - { - p.x = next.x; - } - else if (next.y >= bounds.y && - next.y <= bounds.y + bounds.height) - { - p.y = next.y; - } - if (next.x < bounds.x) - { - p.x = bounds.x; - } - else if (next.x > bounds.x + bounds.width) - { - p.x = bounds.x + bounds.width; - } - if (next.y < bounds.y) - { - p.y = bounds.y; - } - else if (next.y > bounds.y + bounds.height) - { - p.y = bounds.y + bounds.height; - } - } - - return p; - }, - - /** - * Function: EllipsePerimeter - * - * Describes an elliptic perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - EllipsePerimeter: function (bounds, vertex, next, orthogonal) - { - var x = bounds.x; - var y = bounds.y; - var a = bounds.width / 2; - var b = bounds.height / 2; - var cx = x + a; - var cy = y + b; - var px = next.x; - var py = next.y; - - // Calculates straight line equation through - // point and ellipse center y = d * x + h - var dx = parseInt(px - cx); - var dy = parseInt(py - cy); - - if (dx == 0 && dy != 0) - { - return new mxPoint(cx, cy + b * dy / Math.abs(dy)); - } - else if (dx == 0 && dy == 0) - { - return new mxPoint(px, py); - } - - if (orthogonal) - { - if (py >= y && py <= y + bounds.height) - { - var ty = py - cy; - var tx = Math.sqrt(a*a*(1-(ty*ty)/(b*b))) || 0; - - if (px <= x) - { - tx = -tx; - } - - return new mxPoint(cx+tx, py); - } - - if (px >= x && px <= x + bounds.width) - { - var tx = px - cx; - var ty = Math.sqrt(b*b*(1-(tx*tx)/(a*a))) || 0; - - if (py <= y) - { - ty = -ty; - } - - return new mxPoint(px, cy+ty); - } - } - - // Calculates intersection - var d = dy / dx; - var h = cy - d * cx; - var e = a * a * d * d + b * b; - var f = -2 * cx * e; - var g = a * a * d * d * cx * cx + - b * b * cx * cx - - a * a * b * b; - var det = Math.sqrt(f * f - 4 * e * g); - - // Two solutions (perimeter points) - var xout1 = (-f + det) / (2 * e); - var xout2 = (-f - det) / (2 * e); - var yout1 = d * xout1 + h; - var yout2 = d * xout2 + h; - var dist1 = Math.sqrt(Math.pow((xout1 - px), 2) - + Math.pow((yout1 - py), 2)); - var dist2 = Math.sqrt(Math.pow((xout2 - px), 2) - + Math.pow((yout2 - py), 2)); - - // Correct solution - var xout = 0; - var yout = 0; - - if (dist1 < dist2) - { - xout = xout1; - yout = yout1; - } - else - { - xout = xout2; - yout = yout2; - } - - return new mxPoint(xout, yout); - }, - - /** - * Function: RhombusPerimeter - * - * Describes a rhombus (aka diamond) perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - RhombusPerimeter: function (bounds, vertex, next, orthogonal) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - var cx = x + w / 2; - var cy = y + h / 2; - - var px = next.x; - var py = next.y; - - // Special case for intersecting the diamond's corners - if (cx == px) - { - if (cy > py) - { - return new mxPoint(cx, y); // top - } - else - { - return new mxPoint(cx, y + h); // bottom - } - } - else if (cy == py) - { - if (cx > px) - { - return new mxPoint(x, cy); // left - } - else - { - return new mxPoint(x + w, cy); // right - } - } - - var tx = cx; - var ty = cy; - - if (orthogonal) - { - if (px >= x && px <= x + w) - { - tx = px; - } - else if (py >= y && py <= y + h) - { - ty = py; - } - } - - // In which quadrant will the intersection be? - // set the slope and offset of the border line accordingly - if (px < cx) - { - if (py < cy) - { - return mxUtils.intersection(px, py, tx, ty, cx, y, x, cy); - } - else - { - return mxUtils.intersection(px, py, tx, ty, cx, y + h, x, cy); - } - } - else if (py < cy) - { - return mxUtils.intersection(px, py, tx, ty, cx, y, x + w, cy); - } - else - { - return mxUtils.intersection(px, py, tx, ty, cx, y + h, x + w, cy); - } - }, - - /** - * Function: TrianglePerimeter - * - * Describes a triangle perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - TrianglePerimeter: function (bounds, vertex, next, orthogonal) - { - var direction = (vertex != null) ? - vertex.style[mxConstants.STYLE_DIRECTION] : null; - var vertical = direction == mxConstants.DIRECTION_NORTH || - direction == mxConstants.DIRECTION_SOUTH; - - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - var cx = x + w / 2; - var cy = y + h / 2; - - var start = new mxPoint(x, y); - var corner = new mxPoint(x + w, cy); - var end = new mxPoint(x, y + h); - - if (direction == mxConstants.DIRECTION_NORTH) - { - start = end; - corner = new mxPoint(cx, y); - end = new mxPoint(x + w, y + h); - } - else if (direction == mxConstants.DIRECTION_SOUTH) - { - corner = new mxPoint(cx, y + h); - end = new mxPoint(x + w, y); - } - else if (direction == mxConstants.DIRECTION_WEST) - { - start = new mxPoint(x + w, y); - corner = new mxPoint(x, cy); - end = new mxPoint(x + w, y + h); - } - - var dx = next.x - cx; - var dy = next.y - cy; - - var alpha = (vertical) ? Math.atan2(dx, dy) : Math.atan2(dy, dx); - var t = (vertical) ? Math.atan2(w, h) : Math.atan2(h, w); - - var base = false; - - if (direction == mxConstants.DIRECTION_NORTH || - direction == mxConstants.DIRECTION_WEST) - { - base = alpha > -t && alpha < t; - } - else - { - base = alpha < -Math.PI + t || alpha > Math.PI - t; - } - - var result = null; - - if (base) - { - if (orthogonal && ((vertical && next.x >= start.x && next.x <= end.x) || - (!vertical && next.y >= start.y && next.y <= end.y))) - { - if (vertical) - { - result = new mxPoint(next.x, start.y); - } - else - { - result = new mxPoint(start.x, next.y); - } - } - else - { - if (direction == mxConstants.DIRECTION_NORTH) - { - result = new mxPoint(x + w / 2 + h * Math.tan(alpha) / 2, - y + h); - } - else if (direction == mxConstants.DIRECTION_SOUTH) - { - result = new mxPoint(x + w / 2 - h * Math.tan(alpha) / 2, - y); - } - else if (direction == mxConstants.DIRECTION_WEST) - { - result = new mxPoint(x + w, y + h / 2 + - w * Math.tan(alpha) / 2); - } - else - { - result = new mxPoint(x, y + h / 2 - - w * Math.tan(alpha) / 2); - } - } - } - else - { - if (orthogonal) - { - var pt = new mxPoint(cx, cy); - - if (next.y >= y && next.y <= y + h) - { - pt.x = (vertical) ? cx : ( - (direction == mxConstants.DIRECTION_WEST) ? - x + w : x); - pt.y = next.y; - } - else if (next.x >= x && next.x <= x + w) - { - pt.x = next.x; - pt.y = (!vertical) ? cy : ( - (direction == mxConstants.DIRECTION_NORTH) ? - y + h : y); - } - - // Compute angle - dx = next.x - pt.x; - dy = next.y - pt.y; - - cx = pt.x; - cy = pt.y; - } - - if ((vertical && next.x <= x + w / 2) || - (!vertical && next.y <= y + h / 2)) - { - result = mxUtils.intersection(next.x, next.y, cx, cy, - start.x, start.y, corner.x, corner.y); - } - else - { - result = mxUtils.intersection(next.x, next.y, cx, cy, - corner.x, corner.y, end.x, end.y); - } - } - - if (result == null) - { - result = new mxPoint(cx, cy); - } - - return result; - } -}; diff --git a/src/js/view/mxPrintPreview.js b/src/js/view/mxPrintPreview.js deleted file mode 100644 index 24a65e6..0000000 --- a/src/js/view/mxPrintPreview.js +++ /dev/null @@ -1,801 +0,0 @@ -/** - * $Id: mxPrintPreview.js,v 1.61 2012-05-15 14:12:40 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPrintPreview - * - * Implements printing of a diagram across multiple pages. The following opens - * a print preview for an existing graph: - * - * (code) - * var preview = new mxPrintPreview(graph); - * preview.open(); - * (end) - * - * Use <mxUtils.getScaleForPageCount> as follows in order to print the graph - * across a given number of pages: - * - * (code) - * var pageCount = mxUtils.prompt('Enter page count', '1'); - * - * if (pageCount != null) - * { - * var scale = mxUtils.getScaleForPageCount(pageCount, graph); - * var preview = new mxPrintPreview(graph, scale); - * preview.open(); - * } - * (end) - * - * Headers: - * - * Apart from setting the title argument in the mxPrintPreview constructor you - * can override <renderPage> as follows to add a header to any page: - * - * (code) - * var oldRenderPage = mxPrintPreview.prototype.renderPage; - * mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, scale, pageNumber) - * { - * var div = oldRenderPage.apply(this, arguments); - * - * var header = document.createElement('div'); - * header.style.position = 'absolute'; - * header.style.top = '0px'; - * header.style.width = '100%'; - * header.style.textAlign = 'right'; - * mxUtils.write(header, 'Your header here - Page ' + pageNumber + ' / ' + this.pageCount); - * div.firstChild.appendChild(header); - * - * return div; - * }; - * (end) - * - * Page Format: - * - * For landscape printing, use <mxConstants.PAGE_FORMAT_A4_LANDSCAPE> as - * the pageFormat in <mxUtils.getScaleForPageCount> and <mxPrintPreview>. - * Keep in mind that one can not set the defaults for the print dialog - * of the operating system from JavaScript so the user must manually choose - * a page format that matches this setting. - * - * You can try passing the following CSS directive to <open> to set the - * page format in the print dialog to landscape. However, this CSS - * directive seems to be ignored in most major browsers, including IE. - * - * (code) - * @page { - * size: landscape; - * } - * (end) - * - * Note that the print preview behaves differently in IE when used from the - * filesystem or via HTTP so printing should always be tested via HTTP. - * - * If you are using a DOCTYPE in the source page you can override <getDoctype> - * and provide the same DOCTYPE for the print preview if required. Here is - * an example for IE8 standards mode. - * - * (code) - * var preview = new mxPrintPreview(graph); - * preview.getDoctype = function() - * { - * return '<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=5,IE=8" ><![endif]-->'; - * }; - * preview.open(); - * (end) - * - * Constructor: mxPrintPreview - * - * Constructs a new print preview for the given parameters. - * - * Parameters: - * - * graph - <mxGraph> to be previewed. - * scale - Optional scale of the output. Default is 1 / <mxGraph.pageScale>. - * border - Border in pixels along each side of every page. Note that the - * actual print function in the browser will add another border for - * printing. - * pageFormat - <mxRectangle> that specifies the page format (in pixels). - * This should match the page format of the printer. Default uses the - * <mxGraph.pageFormat> of the given graph. - * x0 - Optional left offset of the output. Default is 0. - * y0 - Optional top offset of the output. Default is 0. - * borderColor - Optional color of the page border. Default is no border. - * Note that a border is sometimes useful to highlight the printed page - * border in the print preview of the browser. - * title - Optional string that is used for the window title. Default - * is 'Printer-friendly version'. - * pageSelector - Optional boolean that specifies if the page selector - * should appear in the window with the print preview. Default is true. - */ -function mxPrintPreview(graph, scale, pageFormat, border, x0, y0, borderColor, title, pageSelector) -{ - this.graph = graph; - this.scale = (scale != null) ? scale : 1 / graph.pageScale; - this.border = (border != null) ? border : 0; - this.pageFormat = (pageFormat != null) ? pageFormat : graph.pageFormat; - this.title = (title != null) ? title : 'Printer-friendly version'; - this.x0 = (x0 != null) ? x0 : 0; - this.y0 = (y0 != null) ? y0 : 0; - this.borderColor = borderColor; - this.pageSelector = (pageSelector != null) ? pageSelector : true; -}; - -/** - * Variable: graph - * - * Reference to the <mxGraph> that should be previewed. - */ -mxPrintPreview.prototype.graph = null; - -/** - * Variable: pageFormat - * - * Holds the <mxRectangle> that defines the page format. - */ -mxPrintPreview.prototype.pageFormat = null; - -/** - * Variable: scale - * - * Holds the scale of the print preview. - */ -mxPrintPreview.prototype.scale = null; - -/** - * Variable: border - * - * The border inset around each side of every page in the preview. This is set - * to 0 if autoOrigin is false. - */ -mxPrintPreview.prototype.border = 0; - -/** -/** - * Variable: x0 - * - * Holds the horizontal offset of the output. - */ -mxPrintPreview.prototype.x0 = 0; - -/** - * Variable: y0 - * - * Holds the vertical offset of the output. - */ -mxPrintPreview.prototype.y0 = 0; - -/** - * Variable: autoOrigin - * - * Specifies if the origin should be automatically computed based on the top, - * left corner of the actual diagram contents. If this is set to false then the - * values for <x0> and <y0> will be overridden in <open>. Default is true. - */ -mxPrintPreview.prototype.autoOrigin = true; - -/** - * Variable: printOverlays - * - * Specifies if overlays should be printed. Default is false. - */ -mxPrintPreview.prototype.printOverlays = false; - -/** - * Variable: borderColor - * - * Holds the color value for the page border. - */ -mxPrintPreview.prototype.borderColor = null; - -/** - * Variable: title - * - * Holds the title of the preview window. - */ -mxPrintPreview.prototype.title = null; - -/** - * Variable: pageSelector - * - * Boolean that specifies if the page selector should be - * displayed. Default is true. - */ -mxPrintPreview.prototype.pageSelector = null; - -/** - * Variable: wnd - * - * Reference to the preview window. - */ -mxPrintPreview.prototype.wnd = null; - -/** - * Variable: pageCount - * - * Holds the actual number of pages in the preview. - */ -mxPrintPreview.prototype.pageCount = 0; - -/** - * Function: getWindow - * - * Returns <wnd>. - */ -mxPrintPreview.prototype.getWindow = function() -{ - return this.wnd; -}; - -/** - * Function: getDocType - * - * Returns the string that should go before the HTML tag in the print preview - * page. This implementation returns an empty string. - */ -mxPrintPreview.prototype.getDoctype = function() -{ - return ''; -}; - -/** - * Function: open - * - * Shows the print preview window. The window is created here if it does - * not exist. - * - * Parameters: - * - * css - Optional CSS string to be used in the new page's head section. - */ -mxPrintPreview.prototype.open = function(css) -{ - // Closing the window while the page is being rendered may cause an - // exception in IE. This and any other exceptions are simply ignored. - var previousInitializeOverlay = this.graph.cellRenderer.initializeOverlay; - var div = null; - - try - { - // Temporarily overrides the method to redirect rendering of overlays - // to the draw pane so that they are visible in the printout - if (this.printOverlays) - { - this.graph.cellRenderer.initializeOverlay = function(state, overlay) - { - overlay.init(state.view.getDrawPane()); - }; - } - - if (this.wnd == null) - { - this.wnd = window.open(); - var doc = this.wnd.document; - var dt = this.getDoctype(); - - if (dt != null && dt.length > 0) - { - doc.writeln(dt); - } - - doc.writeln('<html>'); - doc.writeln('<head>'); - this.writeHead(doc, css); - doc.writeln('</head>'); - doc.writeln('<body class="mxPage">'); - - // Adds all required stylesheets and namespaces - mxClient.link('stylesheet', mxClient.basePath + '/css/common.css', doc); - - if (mxClient.IS_IE && document.documentMode != 9) - { - doc.namespaces.add('v', 'urn:schemas-microsoft-com:vml'); - doc.namespaces.add('o', 'urn:schemas-microsoft-com:office:office'); - var ss = doc.createStyleSheet(); - ss.cssText = 'v\\:*{behavior:url(#default#VML)}o\\:*{behavior:url(#default#VML)}'; - mxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css', doc); - } - - // Computes the horizontal and vertical page count - var bounds = this.graph.getGraphBounds().clone(); - var currentScale = this.graph.getView().getScale(); - var sc = currentScale / this.scale; - var tr = this.graph.getView().getTranslate(); - - // Uses the absolute origin with no offset for all printing - if (!this.autoOrigin) - { - this.x0 = -tr.x * this.scale; - this.y0 = -tr.y * this.scale; - bounds.width += bounds.x; - bounds.height += bounds.y; - bounds.x = 0; - bounds.y = 0; - this.border = 0; - } - - // Compute the unscaled, untranslated bounds to find - // the number of vertical and horizontal pages - bounds.width /= sc; - bounds.height /= sc; - - // Store the available page area - var availableWidth = this.pageFormat.width - (this.border * 2); - var availableHeight = this.pageFormat.height - (this.border * 2); - - var hpages = Math.max(1, Math.ceil((bounds.width + this.x0) / availableWidth)); - var vpages = Math.max(1, Math.ceil((bounds.height + this.y0) / availableHeight)); - this.pageCount = hpages * vpages; - - var writePageSelector = mxUtils.bind(this, function() - { - if (this.pageSelector && (vpages > 1 || hpages > 1)) - { - var table = this.createPageSelector(vpages, hpages); - doc.body.appendChild(table); - - // Workaround for position: fixed which isn't working in IE - if (mxClient.IS_IE) - { - table.style.position = 'absolute'; - - var update = function() - { - table.style.top = (doc.body.scrollTop + 10) + 'px'; - }; - - mxEvent.addListener(this.wnd, 'scroll', function(evt) - { - update(); - }); - - mxEvent.addListener(this.wnd, 'resize', function(evt) - { - update(); - }); - } - } - }); - - // Stores pages for later retrieval - var pages = null; - - // Workaround for aspect of image shapes updated asynchronously - // in VML so we need to fetch the markup of the DIV containing - // the image after the udpate of the style of the DOM node. - // LATER: Allow document for display markup to be customized. - if (mxClient.IS_IE && document.documentMode != 9) - { - pages = []; - - // Overrides asynchronous loading of images for fetching HTML markup - var waitCounter = 0; - var isDone = false; - - var mxImageShapeScheduleUpdateAspect = mxImageShape.prototype.scheduleUpdateAspect; - var mxImageShapeUpdateAspect = mxImageShape.prototype.updateAspect; - - var writePages = function() - { - if (isDone && waitCounter == 0) - { - // Restores previous implementations - mxImageShape.prototype.scheduleUpdateAspect = mxImageShapeScheduleUpdateAspect; - mxImageShape.prototype.updateAspect = mxImageShapeUpdateAspect; - - var markup = ''; - - for (var i = 0; i < pages.length; i++) - { - markup += pages[i].outerHTML; - pages[i].parentNode.removeChild(pages[i]); - - if (i < pages.length - 1) - { - markup += '<hr/>'; - } - } - - doc.body.innerHTML = markup; - writePageSelector(); - } - }; - - // Overrides functions to implement wait counter - mxImageShape.prototype.scheduleUpdateAspect = function() - { - waitCounter++; - mxImageShapeScheduleUpdateAspect.apply(this, arguments); - }; - - // Overrides functions to implement wait counter - mxImageShape.prototype.updateAspect = function() - { - mxImageShapeUpdateAspect.apply(this, arguments); - waitCounter--; - writePages(); - }; - } - - // Appends each page to the page output for printing, making - // sure there will be a page break after each page (ie. div) - for (var i = 0; i < vpages; i++) - { - var dy = i * availableHeight / this.scale - this.y0 / this.scale + - (bounds.y - tr.y * currentScale) / currentScale; - - for (var j = 0; j < hpages; j++) - { - if (this.wnd == null) - { - return null; - } - - var dx = j * availableWidth / this.scale - this.x0 / this.scale + - (bounds.x - tr.x * currentScale) / currentScale; - var pageNum = i * hpages + j + 1; - - div = this.renderPage(this.pageFormat.width, this.pageFormat.height, - -dx, -dy, this.scale, pageNum); - - // Gives the page a unique ID for later accessing the page - div.setAttribute('id', 'mxPage-'+pageNum); - - // Border of the DIV (aka page) inside the document - if (this.borderColor != null) - { - div.style.borderColor = this.borderColor; - div.style.borderStyle = 'solid'; - div.style.borderWidth = '1px'; - } - - // Needs to be assigned directly because IE doesn't support - // child selectors, eg. body > div { background: white; } - div.style.background = 'white'; - - if (i < vpages - 1 || j < hpages - 1) - { - div.style.pageBreakAfter = 'always'; - } - - // NOTE: We are dealing with cross-window DOM here, which - // is a problem in IE, so we copy the HTML markup instead. - // The underlying problem is that the graph display markup - // creation (in mxShape, mxGraphView) is hardwired to using - // document.createElement and hence we must use document - // to create the complete page and then copy it over to the - // new window.document. This can be fixed later by using the - // ownerDocument of the container in mxShape and mxGraphView. - if (mxClient.IS_IE) - { - // For some obscure reason, removing the DIV from the - // parent before fetching its outerHTML has missing - // fillcolor properties and fill children, so the div - // must be removed afterwards to keep the fillcolors. - // For delayed output we remote the DIV from the - // original document when we write out all pages. - doc.writeln(div.outerHTML); - - if (pages != null) - { - pages.push(div); - } - else - { - div.parentNode.removeChild(div); - } - } - else - { - div.parentNode.removeChild(div); - doc.body.appendChild(div); - } - - if (i < vpages - 1 || j < hpages - 1) - { - var hr = doc.createElement('hr'); - hr.className = 'mxPageBreak'; - doc.body.appendChild(hr); - } - } - } - - doc.writeln('</body>'); - doc.writeln('</html>'); - doc.close(); - - // Marks the printing complete for async handling - if (pages != null) - { - isDone = true; - writePages(); - } - else - { - writePageSelector(); - } - - // Removes all event handlers in the print output - mxEvent.release(doc.body); - } - - this.wnd.focus(); - } - catch (e) - { - // Removes the DIV from the document in case of an error - if (div != null && div.parentNode != null) - { - div.parentNode.removeChild(div); - } - } - finally - { - this.graph.cellRenderer.initializeOverlay = previousInitializeOverlay; - } - - return this.wnd; -}; - -/** - * Function: writeHead - * - * Writes the HEAD section into the given document, without the opening - * and closing HEAD tags. - */ -mxPrintPreview.prototype.writeHead = function(doc, css) -{ - if (this.title != null) - { - doc.writeln('<title>' + this.title + '</title>'); - } - - // Makes sure no horizontal rulers are printed - doc.writeln('<style type="text/css">'); - doc.writeln('@media print {'); - doc.writeln(' table.mxPageSelector { display: none; }'); - doc.writeln(' hr.mxPageBreak { display: none; }'); - doc.writeln('}'); - doc.writeln('@media screen {'); - - // NOTE: position: fixed is not supported in IE, so the page selector - // position (absolute) needs to be updated in IE (see below) - doc.writeln(' table.mxPageSelector { position: fixed; right: 10px; top: 10px;' + - 'font-family: Arial; font-size:10pt; border: solid 1px darkgray;' + - 'background: white; border-collapse:collapse; }'); - doc.writeln(' table.mxPageSelector td { border: solid 1px gray; padding:4px; }'); - doc.writeln(' body.mxPage { background: gray; }'); - doc.writeln('}'); - - if (css != null) - { - doc.writeln(css); - } - - doc.writeln('</style>'); -}; - -/** - * Function: createPageSelector - * - * Creates the page selector table. - */ -mxPrintPreview.prototype.createPageSelector = function(vpages, hpages) -{ - var doc = this.wnd.document; - var table = doc.createElement('table'); - table.className = 'mxPageSelector'; - table.setAttribute('border', '0'); - - var tbody = doc.createElement('tbody'); - - for (var i = 0; i < vpages; i++) - { - var row = doc.createElement('tr'); - - for (var j = 0; j < hpages; j++) - { - var pageNum = i * hpages + j + 1; - var cell = doc.createElement('td'); - - // Needs anchor for all browers to work without JavaScript - // LATER: Does not work in Firefox because the generated document - // has the URL of the opening document, the anchor is appended - // to that URL and the full URL is loaded on click. - if (!mxClient.IS_NS || mxClient.IS_SF || mxClient.IS_GC) - { - var a = doc.createElement('a'); - a.setAttribute('href', '#mxPage-' + pageNum); - mxUtils.write(a, pageNum, doc); - cell.appendChild(a); - } - else - { - mxUtils.write(cell, pageNum, doc); - } - - row.appendChild(cell); - } - - tbody.appendChild(row); - } - - table.appendChild(tbody); - - return table; -}; - -/** - * Function: renderPage - * - * Creates a DIV that prints a single page of the given - * graph using the given scale and returns the DIV that - * represents the page. - * - * Parameters: - * - * w - Width of the page in pixels. - * h - Height of the page in pixels. - * dx - Horizontal translation for the diagram. - * dy - Vertical translation for the diagram. - * scale - Scale for the diagram. - * pageNumber - Number of the page to be rendered. - */ -mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, scale, pageNumber) -{ - var div = document.createElement('div'); - - try - { - div.style.width = w + 'px'; - div.style.height = h + 'px'; - div.style.overflow = 'hidden'; - div.style.pageBreakInside = 'avoid'; - - var innerDiv = document.createElement('div'); - innerDiv.style.top = this.border + 'px'; - innerDiv.style.left = this.border + 'px'; - innerDiv.style.width = (w - 2 * this.border) + 'px'; - innerDiv.style.height = (h - 2 * this.border) + 'px'; - innerDiv.style.overflow = 'hidden'; - - if (this.graph.dialect == mxConstants.DIALECT_VML) - { - innerDiv.style.position = 'absolute'; - } - - div.appendChild(innerDiv); - document.body.appendChild(div); - var view = this.graph.getView(); - - var previousContainer = this.graph.container; - this.graph.container = innerDiv; - - var canvas = view.getCanvas(); - var backgroundPane = view.getBackgroundPane(); - var drawPane = view.getDrawPane(); - var overlayPane = view.getOverlayPane(); - - if (this.graph.dialect == mxConstants.DIALECT_SVG) - { - view.createSvg(); - } - else if (this.graph.dialect == mxConstants.DIALECT_VML) - { - view.createVml(); - } - else - { - view.createHtml(); - } - - // Disables events on the view - var eventsEnabled = view.isEventsEnabled(); - view.setEventsEnabled(false); - - // Disables the graph to avoid cursors - var graphEnabled = this.graph.isEnabled(); - this.graph.setEnabled(false); - - // Resets the translation - var translate = view.getTranslate(); - view.translate = new mxPoint(dx, dy); - - var temp = null; - - try - { - // Creates the temporary cell states in the view and - // draws them onto the temporary DOM nodes in the view - var model = this.graph.getModel(); - var cells = [model.getRoot()]; - temp = new mxTemporaryCellStates(view, scale, cells); - } - finally - { - // Removes overlay pane with selection handles - // controls and icons from the print output - if (mxClient.IS_IE) - { - view.overlayPane.innerHTML = ''; - } - else - { - // Removes everything but the SVG node - var tmp = innerDiv.firstChild; - - while (tmp != null) - { - var next = tmp.nextSibling; - var name = tmp.nodeName.toLowerCase(); - - // Note: Width and heigh are required in FF 11 - if (name == 'svg') - { - tmp.setAttribute('width', parseInt(innerDiv.style.width)); - tmp.setAttribute('height', parseInt(innerDiv.style.height)); - } - // Tries to fetch all text labels and only text labels - else if (tmp.style.cursor != 'default' && name != 'table') - { - tmp.parentNode.removeChild(tmp); - } - - tmp = next; - } - } - - // Completely removes the overlay pane to remove more handles - view.overlayPane.parentNode.removeChild(view.overlayPane); - - // Restores the state of the view - this.graph.setEnabled(graphEnabled); - this.graph.container = previousContainer; - view.canvas = canvas; - view.backgroundPane = backgroundPane; - view.drawPane = drawPane; - view.overlayPane = overlayPane; - view.translate = translate; - temp.destroy(); - view.setEventsEnabled(eventsEnabled); - } - } - catch (e) - { - div.parentNode.removeChild(div); - div = null; - - throw e; - } - - return div; -}; - -/** - * Function: print - * - * Opens the print preview and shows the print dialog. - */ -mxPrintPreview.prototype.print = function() -{ - var wnd = this.open(); - - if (wnd != null) - { - wnd.print(); - } -}; - -/** - * Function: close - * - * Closes the print preview window. - */ -mxPrintPreview.prototype.close = function() -{ - if (this.wnd != null) - { - this.wnd.close(); - this.wnd = null; - } -}; diff --git a/src/js/view/mxSpaceManager.js b/src/js/view/mxSpaceManager.js deleted file mode 100644 index 2a2dd11..0000000 --- a/src/js/view/mxSpaceManager.js +++ /dev/null @@ -1,460 +0,0 @@ -/** - * $Id: mxSpaceManager.js,v 1.9 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSpaceManager - * - * In charge of moving cells after a resize. - * - * Constructor: mxSpaceManager - * - * Constructs a new automatic layout for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxSpaceManager(graph, shiftRightwards, shiftDownwards, extendParents) -{ - this.resizeHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.foldHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.shiftRightwards = (shiftRightwards != null) ? shiftRightwards : true; - this.shiftDownwards = (shiftDownwards != null) ? shiftDownwards : true; - this.extendParents = (extendParents != null) ? extendParents : true; - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxSpaceManager.prototype = new mxEventSource(); -mxSpaceManager.prototype.constructor = mxSpaceManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxSpaceManager.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.enabled = true; - -/** - * Variable: shiftRightwards - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.shiftRightwards = true; - -/** - * Variable: shiftDownwards - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.shiftDownwards = true; - -/** - * Variable: extendParents - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.extendParents = true; - -/** - * Variable: resizeHandler - * - * Holds the function that handles the move event. - */ -mxSpaceManager.prototype.resizeHandler = null; - -/** - * Variable: foldHandler - * - * Holds the function that handles the fold event. - */ -mxSpaceManager.prototype.foldHandler = null; - -/** - * Function: isCellIgnored - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.isCellIgnored = function(cell) -{ - return !this.getGraph().getModel().isVertex(cell); -}; - -/** - * Function: isCellShiftable - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.isCellShiftable = function(cell) -{ - return this.getGraph().getModel().isVertex(cell) && - this.getGraph().isCellMovable(cell); -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isShiftRightwards - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isShiftRightwards = function() -{ - return this.shiftRightwards; -}; - -/** - * Function: setShiftRightwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setShiftRightwards = function(value) -{ - this.shiftRightwards = value; -}; - -/** - * Function: isShiftDownwards - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isShiftDownwards = function() -{ - return this.shiftDownwards; -}; - -/** - * Function: setShiftDownwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setShiftDownwards = function(value) -{ - this.shiftDownwards = value; -}; - -/** - * Function: isExtendParents - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isExtendParents = function() -{ - return this.extendParents; -}; - -/** - * Function: setShiftDownwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setExtendParents = function(value) -{ - this.extendParents = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this layout operates on. - */ -mxSpaceManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - this.graph.removeListener(this.resizeHandler); - this.graph.removeListener(this.foldHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - this.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler); - this.graph.addListener(mxEvent.FOLD_CELLS, this.foldHandler); - } -}; - -/** - * Function: cellsResized - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - Array of <mxCells> that have been resized. - */ -mxSpaceManager.prototype.cellsResized = function(cells) -{ - if (cells != null) - { - var model = this.graph.getModel(); - - // Raising the update level should not be required - // since only one call is made below - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (!this.isCellIgnored(cells[i])) - { - this.cellResized(cells[i]); - break; - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: cellResized - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxSpaceManager.prototype.cellResized = function(cell) -{ - var graph = this.getGraph(); - var view = graph.getView(); - var model = graph.getModel(); - - var state = view.getState(cell); - var pstate = view.getState(model.getParent(cell)); - - if (state != null && - pstate != null) - { - var cells = this.getCellsToShift(state); - var geo = model.getGeometry(cell); - - if (cells != null && - geo != null) - { - var tr = view.translate; - var scale = view.scale; - - var x0 = state.x - pstate.origin.x - tr.x * scale; - var y0 = state.y - pstate.origin.y - tr.y * scale; - var right = state.x + state.width; - var bottom = state.y + state.height; - - var dx = state.width - geo.width * scale + x0 - geo.x * scale; - var dy = state.height - geo.height * scale + y0 - geo.y * scale; - - var fx = 1 - geo.width * scale / state.width; - var fy = 1 - geo.height * scale / state.height; - - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != cell && - this.isCellShiftable(cells[i])) - { - this.shiftCell(cells[i], dx, dy, x0, y0, right, bottom, fx, fy, - this.isExtendParents() && - graph.isExtendParent(cells[i])); - } - } - } - finally - { - model.endUpdate(); - } - } - } -}; - -/** - * Function: shiftCell - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxSpaceManager.prototype.shiftCell = function(cell, dx, dy, Ox0, y0, right, - bottom, fx, fy, extendParent) -{ - var graph = this.getGraph(); - var state = graph.getView().getState(cell); - - if (state != null) - { - var model = graph.getModel(); - var geo = model.getGeometry(cell); - - if (geo != null) - { - model.beginUpdate(); - try - { - if (this.isShiftRightwards()) - { - if (state.x >= right) - { - geo = geo.clone(); - geo.translate(-dx, 0); - } - else - { - var tmpDx = Math.max(0, state.x - x0); - geo = geo.clone(); - geo.translate(-fx * tmpDx, 0); - } - } - - if (this.isShiftDownwards()) - { - if (state.y >= bottom) - { - geo = geo.clone(); - geo.translate(0, -dy); - } - else - { - var tmpDy = Math.max(0, state.y - y0); - geo = geo.clone(); - geo.translate(0, -fy * tmpDy); - } - } - - if (geo != model.getGeometry(cell)) - { - model.setGeometry(cell, geo); - - // Parent size might need to be updated if this - // is seen as part of the resize - if (extendParent) - { - graph.extendParent(cell); - } - } - } - finally - { - model.endUpdate(); - } - } - } -}; - -/** - * Function: getCellsToShift - * - * Returns the cells to shift after a resize of the - * specified <mxCellState>. - */ -mxSpaceManager.prototype.getCellsToShift = function(state) -{ - var graph = this.getGraph(); - var parent = graph.getModel().getParent(state.cell); - var down = this.isShiftDownwards(); - var right = this.isShiftRightwards(); - - return graph.getCellsBeyond(state.x + ((down) ? 0 : state.width), - state.y + ((down && right) ? 0 : state.height), parent, right, down); -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxSpaceManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxStyleRegistry.js b/src/js/view/mxStyleRegistry.js deleted file mode 100644 index 6ad878d..0000000 --- a/src/js/view/mxStyleRegistry.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * $Id: mxStyleRegistry.js,v 1.10 2011-04-27 10:15:39 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxStyleRegistry = -{ - /** - * Class: mxStyleRegistry - * - * Singleton class that acts as a global converter from string to object values - * in a style. This is currently only used to perimeters and edge styles. - * - * Variable: values - * - * Maps from strings to objects. - */ - values: [], - - /** - * Function: putValue - * - * Puts the given object into the registry under the given name. - */ - putValue: function(name, obj) - { - mxStyleRegistry.values[name] = obj; - }, - - /** - * Function: getValue - * - * Returns the value associated with the given name. - */ - getValue: function(name) - { - return mxStyleRegistry.values[name]; - }, - - /** - * Function: getName - * - * Returns the name for the given value. - */ - getName: function(value) - { - for (var key in mxStyleRegistry.values) - { - if (mxStyleRegistry.values[key] == value) - { - return key; - } - } - - return null; - } - -}; - -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ELBOW, mxEdgeStyle.ElbowConnector); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ENTITY_RELATION, mxEdgeStyle.EntityRelation); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_LOOP, mxEdgeStyle.Loop); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SIDETOSIDE, mxEdgeStyle.SideToSide); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_TOPTOBOTTOM, mxEdgeStyle.TopToBottom); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ORTHOGONAL, mxEdgeStyle.OrthConnector); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SEGMENT, mxEdgeStyle.SegmentConnector); - -mxStyleRegistry.putValue(mxConstants.PERIMETER_ELLIPSE, mxPerimeter.EllipsePerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_RECTANGLE, mxPerimeter.RectanglePerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_RHOMBUS, mxPerimeter.RhombusPerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_TRIANGLE, mxPerimeter.TrianglePerimeter); diff --git a/src/js/view/mxStylesheet.js b/src/js/view/mxStylesheet.js deleted file mode 100644 index 82a520e..0000000 --- a/src/js/view/mxStylesheet.js +++ /dev/null @@ -1,266 +0,0 @@ -/** - * $Id: mxStylesheet.js,v 1.35 2010-03-26 10:24:58 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxStylesheet - * - * Defines the appearance of the cells in a graph. See <putCellStyle> for an - * example of creating a new cell style. It is recommended to use objects, not - * arrays for holding cell styles. Existing styles can be cloned using - * <mxUtils.clone> and turned into a string for debugging using - * <mxUtils.toString>. - * - * Default Styles: - * - * The stylesheet contains two built-in styles, which are used if no style is - * defined for a cell: - * - * defaultVertex - Default style for vertices - * defaultEdge - Default style for edges - * - * Example: - * - * (code) - * var vertexStyle = stylesheet.getDefaultVertexStyle(); - * vertexStyle[mxConstants.ROUNDED] = true; - * var edgeStyle = stylesheet.getDefaultEdgeStyle(); - * edgeStyle[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation; - * (end) - * - * Modifies the built-in default styles. - * - * To avoid the default style for a cell, add a leading semicolon - * to the style definition, eg. - * - * (code) - * ;shadow=1 - * (end) - * - * Removing keys: - * - * For removing a key in a cell style of the form [stylename;|key=value;] the - * special value none can be used, eg. highlight;fillColor=none - * - * See also the helper methods in mxUtils to modify strings of this format, - * namely <mxUtils.setStyle>, <mxUtils.indexOfStylename>, - * <mxUtils.addStylename>, <mxUtils.removeStylename>, - * <mxUtils.removeAllStylenames> and <mxUtils.setStyleFlag>. - * - * Constructor: mxStylesheet - * - * Constructs a new stylesheet and assigns default styles. - */ -function mxStylesheet() -{ - this.styles = new Object(); - - this.putDefaultVertexStyle(this.createDefaultVertexStyle()); - this.putDefaultEdgeStyle(this.createDefaultEdgeStyle()); -}; - -/** - * Function: styles - * - * Maps from names to cell styles. Each cell style is a map of key, - * value pairs. - */ -mxStylesheet.prototype.styles; - -/** - * Function: createDefaultVertexStyle - * - * Creates and returns the default vertex style. - */ -mxStylesheet.prototype.createDefaultVertexStyle = function() -{ - var style = new Object(); - - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_FILLCOLOR] = '#C3D9FF'; - style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; - style[mxConstants.STYLE_FONTCOLOR] = '#774400'; - - return style; -}; - -/** - * Function: createDefaultEdgeStyle - * - * Creates and returns the default edge style. - */ -mxStylesheet.prototype.createDefaultEdgeStyle = function() -{ - var style = new Object(); - - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR; - style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; - style[mxConstants.STYLE_FONTCOLOR] = '#446299'; - - return style; -}; - -/** - * Function: putDefaultVertexStyle - * - * Sets the default style for vertices using defaultVertex as the - * stylename. - * - * Parameters: - * style - Key, value pairs that define the style. - */ -mxStylesheet.prototype.putDefaultVertexStyle = function(style) -{ - this.putCellStyle('defaultVertex', style); -}; - -/** - * Function: putDefaultEdgeStyle - * - * Sets the default style for edges using defaultEdge as the stylename. - */ -mxStylesheet.prototype.putDefaultEdgeStyle = function(style) -{ - this.putCellStyle('defaultEdge', style); -}; - -/** - * Function: getDefaultVertexStyle - * - * Returns the default style for vertices. - */ -mxStylesheet.prototype.getDefaultVertexStyle = function() -{ - return this.styles['defaultVertex']; -}; - -/** - * Function: getDefaultEdgeStyle - * - * Sets the default style for edges. - */ -mxStylesheet.prototype.getDefaultEdgeStyle = function() -{ - return this.styles['defaultEdge']; -}; - -/** - * Function: putCellStyle - * - * Stores the given map of key, value pairs under the given name in - * <styles>. - * - * Example: - * - * The following example adds a new style called 'rounded' into an - * existing stylesheet: - * - * (code) - * var style = new Object(); - * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - * style[mxConstants.STYLE_ROUNDED] = true; - * graph.getStylesheet().putCellStyle('rounded', style); - * (end) - * - * In the above example, the new style is an object. The possible keys of - * the object are all the constants in <mxConstants> that start with STYLE - * and the values are either JavaScript objects, such as - * <mxPerimeter.RightAngleRectanglePerimeter> (which is in fact a function) - * or expressions, such as true. Note that not all keys will be - * interpreted by all shapes (eg. the line shape ignores the fill color). - * The final call to this method associates the style with a name in the - * stylesheet. The style is used in a cell with the following code: - * - * (code) - * model.setStyle(cell, 'rounded'); - * (end) - * - * Parameters: - * - * name - Name for the style to be stored. - * style - Key, value pairs that define the style. - */ -mxStylesheet.prototype.putCellStyle = function(name, style) -{ - this.styles[name] = style; -}; - -/** - * Function: getCellStyle - * - * Returns the cell style for the specified stylename or the given - * defaultStyle if no style can be found for the given stylename. - * - * Parameters: - * - * name - String of the form [(stylename|key=value);] that represents the - * style. - * defaultStyle - Default style to be returned if no style can be found. - */ -mxStylesheet.prototype.getCellStyle = function(name, defaultStyle) -{ - var style = defaultStyle; - - if (name != null && name.length > 0) - { - var pairs = name.split(';'); - - if (style != null && - name.charAt(0) != ';') - { - style = mxUtils.clone(style); - } - else - { - style = new Object(); - } - - // Parses each key, value pair into the existing style - for (var i = 0; i < pairs.length; i++) - { - var tmp = pairs[i]; - var pos = tmp.indexOf('='); - - if (pos >= 0) - { - var key = tmp.substring(0, pos); - var value = tmp.substring(pos + 1); - - if (value == mxConstants.NONE) - { - delete style[key]; - } - else if (mxUtils.isNumeric(value)) - { - style[key] = parseFloat(value); - } - else - { - style[key] = value; - } - } - else - { - // Merges the entries from a named style - var tmpStyle = this.styles[tmp]; - - if (tmpStyle != null) - { - for (var key in tmpStyle) - { - style[key] = tmpStyle[key]; - } - } - } - } - } - - return style; -}; diff --git a/src/js/view/mxSwimlaneManager.js b/src/js/view/mxSwimlaneManager.js deleted file mode 100644 index fe40613..0000000 --- a/src/js/view/mxSwimlaneManager.js +++ /dev/null @@ -1,449 +0,0 @@ -/** - * $Id: mxSwimlaneManager.js,v 1.17 2011-01-14 15:21:10 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSwimlaneManager - * - * Manager for swimlanes and nested swimlanes that sets the size of newly added - * swimlanes to that of their siblings, and propagates changes to the size of a - * swimlane to its siblings, if <siblings> is true, and its ancestors, if - * <bubbling> is true. - * - * Constructor: mxSwimlaneManager - * - * Constructs a new swimlane manager for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxSwimlaneManager(graph, horizontal, addEnabled, resizeEnabled) -{ - this.horizontal = (horizontal != null) ? horizontal : true; - this.addEnabled = (addEnabled != null) ? addEnabled : true; - this.resizeEnabled = (resizeEnabled != null) ? resizeEnabled : true; - - this.addHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled() && this.isAddEnabled()) - { - this.cellsAdded(evt.getProperty('cells')); - } - }); - - this.resizeHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled() && this.isResizeEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxSwimlaneManager.prototype = new mxEventSource(); -mxSwimlaneManager.prototype.constructor = mxSwimlaneManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxSwimlaneManager.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxSwimlaneManager.prototype.enabled = true; - -/** - * Variable: horizontal - * - * Specifies the orientation of the swimlanes. Default is true. - */ -mxSwimlaneManager.prototype.horizontal = true; - -/** - * Variable: addEnabled - * - * Specifies if newly added cells should be resized to match the size of their - * existing siblings. Default is true. - */ -mxSwimlaneManager.prototype.addEnabled = true; - -/** - * Variable: resizeEnabled - * - * Specifies if resizing of swimlanes should be handled. Default is true. - */ -mxSwimlaneManager.prototype.resizeEnabled = true; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxSwimlaneManager.prototype.addHandler = null; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxSwimlaneManager.prototype.resizeHandler = null; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSwimlaneManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSwimlaneManager.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isHorizontal - * - * Returns <horizontal>. - */ -mxSwimlaneManager.prototype.isHorizontal = function() -{ - return this.horizontal; -}; - -/** - * Function: setHorizontal - * - * Sets <horizontal>. - */ -mxSwimlaneManager.prototype.setHorizontal = function(value) -{ - this.horizontal = value; -}; - -/** - * Function: isAddEnabled - * - * Returns <addEnabled>. - */ -mxSwimlaneManager.prototype.isAddEnabled = function() -{ - return this.addEnabled; -}; - -/** - * Function: setAddEnabled - * - * Sets <addEnabled>. - */ -mxSwimlaneManager.prototype.setAddEnabled = function(value) -{ - this.addEnabled = value; -}; - -/** - * Function: isResizeEnabled - * - * Returns <resizeEnabled>. - */ -mxSwimlaneManager.prototype.isResizeEnabled = function() -{ - return this.resizeEnabled; -}; - -/** - * Function: setResizeEnabled - * - * Sets <resizeEnabled>. - */ -mxSwimlaneManager.prototype.setResizeEnabled = function(value) -{ - this.resizeEnabled = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this manager operates on. - */ -mxSwimlaneManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the manager operates on. - */ -mxSwimlaneManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - this.graph.removeListener(this.addHandler); - this.graph.removeListener(this.resizeHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - this.graph.addListener(mxEvent.ADD_CELLS, this.addHandler); - this.graph.addListener(mxEvent.CELLS_RESIZED, this.resizeHandler); - } -}; - -/** - * Function: isSwimlaneIgnored - * - * Returns true if the given swimlane should be ignored. - */ -mxSwimlaneManager.prototype.isSwimlaneIgnored = function(swimlane) -{ - return !this.getGraph().isSwimlane(swimlane); -}; - -/** - * Function: isCellHorizontal - * - * Returns true if the given cell is horizontal. If the given cell is not a - * swimlane, then the global orientation is returned. - */ -mxSwimlaneManager.prototype.isCellHorizontal = function(cell) -{ - if (this.graph.isSwimlane(cell)) - { - var state = this.graph.view.getState(cell); - var style = (state != null) ? state.style : this.graph.getCellStyle(cell); - - return mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, 1) == 1; - } - - return !this.isHorizontal(); -}; - -/** - * Function: cellsAdded - * - * Called if any cells have been added. - * - * Parameters: - * - * cell - Array of <mxCells> that have been added. - */ -mxSwimlaneManager.prototype.cellsAdded = function(cells) -{ - if (cells != null) - { - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (!this.isSwimlaneIgnored(cells[i])) - { - this.swimlaneAdded(cells[i]); - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: swimlaneAdded - * - * Updates the size of the given swimlane to match that of any existing - * siblings swimlanes. - * - * Parameters: - * - * swimlane - <mxCell> that represents the new swimlane. - */ -mxSwimlaneManager.prototype.swimlaneAdded = function(swimlane) -{ - var model = this.getGraph().getModel(); - var parent = model.getParent(swimlane); - var childCount = model.getChildCount(parent); - var geo = null; - - // Finds the first valid sibling swimlane as reference - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (child != swimlane && !this.isSwimlaneIgnored(child)) - { - geo = model.getGeometry(child); - - if (geo != null) - { - break; - } - } - } - - // Applies the size of the refernece to the newly added swimlane - if (geo != null) - { - this.resizeSwimlane(swimlane, geo.width, geo.height); - } -}; - -/** - * Function: cellsResized - * - * Called if any cells have been resizes. Calls <swimlaneResized> for all - * swimlanes where <isSwimlaneIgnored> returns false. - * - * Parameters: - * - * cells - Array of <mxCells> whose size was changed. - */ -mxSwimlaneManager.prototype.cellsResized = function(cells) -{ - if (cells != null) - { - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - // Finds the top-level swimlanes and adds offsets - for (var i = 0; i < cells.length; i++) - { - if (!this.isSwimlaneIgnored(cells[i])) - { - var geo = model.getGeometry(cells[i]); - - if (geo != null) - { - var size = new mxRectangle(0, 0, geo.width, geo.height); - var top = cells[i]; - var current = top; - - while (current != null) - { - top = current; - current = model.getParent(current); - var tmp = (this.graph.isSwimlane(current)) ? - this.graph.getStartSize(current) : - new mxRectangle(); - size.width += tmp.width; - size.height += tmp.height; - } - - this.resizeSwimlane(top, size.width, size.height); - } - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: resizeSwimlane - * - * Called from <cellsResized> for all swimlanes that are not ignored to update - * the size of the siblings and the size of the parent swimlanes, recursively, - * if <bubbling> is true. - * - * Parameters: - * - * swimlane - <mxCell> whose size has changed. - */ -mxSwimlaneManager.prototype.resizeSwimlane = function(swimlane, w, h) -{ - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - if (!this.isSwimlaneIgnored(swimlane)) - { - var geo = model.getGeometry(swimlane); - - if (geo != null) - { - var horizontal = this.isCellHorizontal(swimlane); - - if ((horizontal && geo.height != h) || (!horizontal && geo.width != w)) - { - geo = geo.clone(); - - if (horizontal) - { - geo.height = h; - } - else - { - geo.width = w; - } - - model.setGeometry(swimlane, geo); - } - } - } - - var tmp = (this.graph.isSwimlane(swimlane)) ? - this.graph.getStartSize(swimlane) : - new mxRectangle(); - w -= tmp.width; - h -= tmp.height; - - var childCount = model.getChildCount(swimlane); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(swimlane, i); - this.resizeSwimlane(child, w, h); - } - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxSwimlaneManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxTemporaryCellStates.js b/src/js/view/mxTemporaryCellStates.js deleted file mode 100644 index ce8232c..0000000 --- a/src/js/view/mxTemporaryCellStates.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * $Id: mxTemporaryCellStates.js,v 1.10 2010-04-20 14:43:12 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxTemporaryCellStates - * - * Extends <mxPoint> to implement a 2-dimensional rectangle with double - * precision coordinates. - * - * Constructor: mxRectangle - * - * Constructs a new rectangle for the optional parameters. If no parameters - * are given then the respective default values are used. - */ -function mxTemporaryCellStates(view, scale, cells) -{ - this.view = view; - scale = (scale != null) ? scale : 1; - - // Stores the previous state - this.oldBounds = view.getGraphBounds(); - this.oldStates = view.getStates(); - this.oldScale = view.getScale(); - - // Creates space for new states - view.setStates(new mxDictionary()); - view.setScale(scale); - - if (cells != null) - { - // Creates virtual parent state for validation - var state = view.createState(new mxCell()); - - // Validates the vertices and edges without adding them to - // the model so that the original cells are not modified - for (var i = 0; i < cells.length; i++) - { - view.validateBounds(state, cells[i]); - } - - var bbox = null; - - for (var i = 0; i < cells.length; i++) - { - var bounds = view.validatePoints(state, cells[i]); - - if (bbox == null) - { - bbox = bounds; - } - else - { - bbox.add(bounds); - } - } - - if (bbox == null) - { - bbox = new mxRectangle(); - } - - view.setGraphBounds(bbox); - } -}; - -/** - * Variable: view - * - * Holds the width of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.view = null; - -/** - * Variable: oldStates - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldStates = null; - -/** - * Variable: oldBounds - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldBounds = null; - -/** - * Variable: oldScale - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldScale = null; - -/** - * Function: destroy - * - * Returns the top, left corner as a new <mxPoint>. - */ -mxTemporaryCellStates.prototype.destroy = function() -{ - this.view.setScale(this.oldScale); - this.view.setStates(this.oldStates); - this.view.setGraphBounds(this.oldBounds); -}; |