diff options
Diffstat (limited to 'src/js/layout/hierarchical/mxHierarchicalLayout.js')
-rw-r--r-- | src/js/layout/hierarchical/mxHierarchicalLayout.js | 623 |
1 files changed, 0 insertions, 623 deletions
diff --git a/src/js/layout/hierarchical/mxHierarchicalLayout.js b/src/js/layout/hierarchical/mxHierarchicalLayout.js deleted file mode 100644 index 6ce0e05..0000000 --- a/src/js/layout/hierarchical/mxHierarchicalLayout.js +++ /dev/null @@ -1,623 +0,0 @@ -/** - * $Id: mxHierarchicalLayout.js,v 1.30 2012-12-18 12:41:06 david Exp $ - * Copyright (c) 2005-2012, JGraph Ltd - */ -/** - * Class: mxHierarchicalLayout - * - * A hierarchical layout algorithm. - * - * Constructor: mxHierarchicalLayout - * - * Constructs a new hierarchical layout algorithm. - * - * Arguments: - * - * graph - Reference to the enclosing <mxGraph>. - * orientation - Optional constant that defines the orientation of this - * layout. - * deterministic - Optional boolean that specifies if this layout should be - * deterministic. Default is true. - */ -function mxHierarchicalLayout(graph, orientation, deterministic) -{ - mxGraphLayout.call(this, graph); - this.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH; - this.deterministic = (deterministic != null) ? deterministic : true; -}; - -/** - * Extends mxGraphLayout. - */ -mxHierarchicalLayout.prototype = new mxGraphLayout(); -mxHierarchicalLayout.prototype.constructor = mxHierarchicalLayout; - -/** - * Variable: roots - * - * Holds the array of <mxGraphLayouts> that this layout contains. - */ -mxHierarchicalLayout.prototype.roots = null; - -/** - * Variable: resizeParent - * - * Specifies if the parent should be resized after the layout so that it - * contains all the child cells. Default is false. See also <parentBorder>. - */ -mxHierarchicalLayout.prototype.resizeParent = false; - -/** - * Variable: moveParent - * - * Specifies if the parent should be moved if <resizeParent> is enabled. - * Default is false. - */ -mxHierarchicalLayout.prototype.moveParent = false; - -/** - * Variable: parentBorder - * - * The border to be added around the children if the parent is to be - * resized using <resizeParent>. Default is 0. - */ -mxHierarchicalLayout.prototype.parentBorder = 0; - -/** - * Variable: intraCellSpacing - * - * The spacing buffer added between cells on the same layer. Default is 30. - */ -mxHierarchicalLayout.prototype.intraCellSpacing = 30; - -/** - * Variable: interRankCellSpacing - * - * The spacing buffer added between cell on adjacent layers. Default is 50. - */ -mxHierarchicalLayout.prototype.interRankCellSpacing = 50; - -/** - * Variable: interHierarchySpacing - * - * The spacing buffer between unconnected hierarchies. Default is 60. - */ -mxHierarchicalLayout.prototype.interHierarchySpacing = 60; - -/** - * Variable: parallelEdgeSpacing - * - * The distance between each parallel edge on each ranks for long edges - */ -mxHierarchicalLayout.prototype.parallelEdgeSpacing = 10; - -/** - * Variable: orientation - * - * The position of the root node(s) relative to the laid out graph in. - * Default is <mxConstants.DIRECTION_NORTH>. - */ -mxHierarchicalLayout.prototype.orientation = mxConstants.DIRECTION_NORTH; - -/** - * Variable: fineTuning - * - * Whether or not to perform local optimisations and iterate multiple times - * through the algorithm. Default is true. - */ -mxHierarchicalLayout.prototype.fineTuning = true; - -/** - * - * Variable: tightenToSource - * - * Whether or not to tighten the assigned ranks of vertices up towards - * the source cells. - */ -mxHierarchicalLayout.prototype.tightenToSource = true; - -/** - * Variable: disableEdgeStyle - * - * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are - * modified by the result. Default is true. - */ -mxHierarchicalLayout.prototype.disableEdgeStyle = true; - -/** - * Variable: promoteEdges - * - * Whether or not to promote edges that terminate on vertices with - * different but common ancestry to appear connected to the highest - * siblings in the ancestry chains - */ -mxHierarchicalLayout.prototype.promoteEdges = true; - -/** - * Variable: traverseAncestors - * - * Whether or not to navigate edges whose terminal vertices - * have different parents but are in the same ancestry chain - */ -mxHierarchicalLayout.prototype.traverseAncestors = true; - -/** - * Variable: model - * - * The internal <mxGraphHierarchyModel> formed of the layout. - */ -mxHierarchicalLayout.prototype.model = null; - -/** - * Function: getModel - * - * Returns the internal <mxGraphHierarchyModel> for this layout algorithm. - */ -mxHierarchicalLayout.prototype.getModel = function() -{ - return this.model; -}; - -/** - * Function: execute - * - * Executes the layout for the children of the specified parent. - * - * Parameters: - * - * parent - Parent <mxCell> that contains the children to be laid out. - * roots - Optional starting roots of the layout. - */ -mxHierarchicalLayout.prototype.execute = function(parent, roots) -{ - this.parent = parent; - var model = this.graph.model; - - // If the roots are set and the parent is set, only - // use the roots that are some dependent of the that - // parent. - // If just the root are set, use them as-is - // If just the parent is set use it's immediate - // children as the initial set - - if (roots == null && parent == null) - { - // TODO indicate the problem - return; - } - - if (roots != null && parent != null) - { - var rootsCopy = []; - - for (var i = 0; i < roots.length; i++) - { - - if (model.isAncestor(parent, roots[i])) - { - rootsCopy.push(roots[i]); - } - } - - this.roots = rootsCopy; - } - else - { - this.roots = roots; - } - - model.beginUpdate(); - try - { - this.run(parent); - - if (this.resizeParent && - !this.graph.isCellCollapsed(parent)) - { - this.graph.updateGroupBounds([parent], - this.parentBorder, this.moveParent); - } - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: findRoots - * - * Returns all visible children in the given parent which do not have - * incoming edges. If the result is empty then the children with the - * maximum difference between incoming and outgoing edges are returned. - * This takes into account edges that are being promoted to the given - * root due to invisible children or collapsed cells. - * - * Parameters: - * - * parent - <mxCell> whose children should be checked. - * vertices - array of vertices to limit search to - */ -mxHierarchicalLayout.prototype.findRoots = function(parent, vertices) -{ - var roots = []; - - if (parent != null && vertices != null) - { - var model = this.graph.model; - var best = null; - var maxDiff = -100000; - - for (var i in vertices) - { - var cell = vertices[i]; - - if (model.isVertex(cell) && this.graph.isCellVisible(cell)) - { - var conns = this.getEdges(cell); - var fanOut = 0; - var fanIn = 0; - - for (var k = 0; k < conns.length; k++) - { - var src = this.graph.view.getVisibleTerminal(conns[k], true); - - if (src == cell) - { - fanOut++; - } - else - { - fanIn++; - } - } - - if (fanIn == 0 && fanOut > 0) - { - roots.push(cell); - } - - var diff = fanOut - fanIn; - - if (diff > maxDiff) - { - maxDiff = diff; - best = cell; - } - } - } - - if (roots.length == 0 && best != null) - { - roots.push(best); - } - } - - return roots; -}; - -/** - * Function: getEdges - * - * Returns the connected edges for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose edges should be returned. - */ -mxHierarchicalLayout.prototype.getEdges = function(cell) -{ - var model = this.graph.model; - var edges = []; - var isCollapsed = this.graph.isCellCollapsed(cell); - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - - if (isCollapsed || !this.graph.isCellVisible(child)) - { - edges = edges.concat(model.getEdges(child, true, true)); - } - } - - edges = edges.concat(model.getEdges(cell, true, true)); - var result = []; - - for (var i = 0; i < edges.length; i++) - { - var state = this.graph.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.graph.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.graph.view.getVisibleTerminal(edges[i], false); - - if ((source == target) || ((source != target) && ((target == cell && (this.parent == null || this.graph.isValidAncestor(source, this.parent, this.traverseAncestors))) || - (source == cell && (this.parent == null || - this.graph.isValidAncestor(target, this.parent, this.traverseAncestors)))))) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: run - * - * The API method used to exercise the layout upon the graph description - * and produce a separate description of the vertex position and edge - * routing changes made. It runs each stage of the layout that has been - * created. - */ -mxHierarchicalLayout.prototype.run = function(parent) -{ - // Separate out unconnected hierarchies - var hierarchyVertices = []; - var allVertexSet = []; - - if (this.roots == null && parent != null) - { - var filledVertexSet = this.filterDescendants(parent); - - this.roots = []; - var filledVertexSetEmpty = true; - - // Poor man's isSetEmpty - for (var key in filledVertexSet) - { - if (filledVertexSet[key] != null) - { - filledVertexSetEmpty = false; - break; - } - } - - while (!filledVertexSetEmpty) - { - var candidateRoots = this.findRoots(parent, filledVertexSet); - - for (var i = 0; i < candidateRoots.length; i++) - { - var vertexSet = []; - hierarchyVertices.push(vertexSet); - - this.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet, - hierarchyVertices, filledVertexSet); - } - - for (var i = 0; i < candidateRoots.length; i++) - { - this.roots.push(candidateRoots[i]); - } - - filledVertexSetEmpty = true; - - // Poor man's isSetEmpty - for (var key in filledVertexSet) - { - if (filledVertexSet[key] != null) - { - filledVertexSetEmpty = false; - break; - } - } - } - } - else - { - // Find vertex set as directed traversal from roots - - for (var i = 0; i < roots.length; i++) - { - var vertexSet = []; - hierarchyVertices.push(vertexSet); - - traverse(roots.get(i), true, null, allVertexSet, vertexSet, - hierarchyVertices, null); - } - } - - // Iterate through the result removing parents who have children in this layout - - // Perform a layout for each seperate hierarchy - // Track initial coordinate x-positioning - var initialX = 0; - - for (var i = 0; i < hierarchyVertices.length; i++) - { - var vertexSet = hierarchyVertices[i]; - var tmp = []; - - for (var key in vertexSet) - { - tmp.push(vertexSet[key]); - } - - this.model = new mxGraphHierarchyModel(this, tmp, this.roots, - parent, this.tightenToSource); - - this.cycleStage(parent); - this.layeringStage(); - - this.crossingStage(parent); - initialX = this.placementStage(initialX, parent); - } -}; - -/** - * Function: filterDescendants - * - * Creates an array of descendant cells - */ -mxHierarchicalLayout.prototype.filterDescendants = function(cell) -{ - var model = this.graph.model; - var result = []; - - if (model.isVertex(cell) && cell != this.parent && this.graph.isCellVisible(cell)) - { - result.push(cell); - } - - if (this.traverseAncestors || cell == this.parent - && this.graph.isCellVisible(cell)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - var children = this.filterDescendants(child); - - for (var j = 0; j < children.length; j++) - { - result[mxCellPath.create(children[j])] = children[j]; - } - } - } - - return result; -}; - -/** - * Traverses the (directed) graph invoking the given function for each - * visited vertex and edge. The function is invoked with the current vertex - * and the incoming edge as a parameter. This implementation makes sure - * each vertex is only visited once. The function may return false if the - * traversal should stop at the given vertex. - * - * Parameters: - * - * vertex - <mxCell> that represents the vertex where the traversal starts. - * directed - boolean indicating if edges should only be traversed - * from source to target. Default is true. - * edge - Optional <mxCell> that represents the incoming edge. This is - * null for the first step of the traversal. - * allVertices - Array of cell paths for the visited cells. - */ -mxHierarchicalLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp, - hierarchyVertices, filledVertexSet) -{ - var view = this.graph.view; - var model = this.graph.model; - - if (vertex != null && allVertices != null) - { - // Has this vertex been seen before in any traversal - // And if the filled vertex set is populated, only - // process vertices in that it contains - var vertexID = mxCellPath.create(vertex); - - if ((allVertices[vertexID] == null) - && (filledVertexSet == null ? true : filledVertexSet[vertexID] != null)) - { - if (currentComp[vertexID] == null) - { - currentComp[vertexID] = vertex; - } - if (allVertices[vertexID] == null) - { - allVertices[vertexID] = vertex; - } - - delete filledVertexSet[vertexID]; - - var edgeCount = model.getEdgeCount(vertex); - - if (edgeCount > 0) - { - for (var i = 0; i < edgeCount; i++) - { - var e = model.getEdgeAt(vertex, i); - var isSource = view.getVisibleTerminal(e, true) == vertex; - - if (!directed || isSource) - { - var next = view.getVisibleTerminal(e, !isSource); - currentComp = this.traverse(next, directed, e, allVertices, - currentComp, hierarchyVertices, - filledVertexSet); - } - } - } - } - else - { - if (currentComp[vertexID] == null) - { - // We've seen this vertex before, but not in the current component - // This component and the one it's in need to be merged - - for (var i = 0; i < hierarchyVertices.length; i++) - { - var comp = hierarchyVertices[i]; - - if (comp[vertexID] != null) - { - for (var key in currentComp) - { - comp[key] = currentComp[key]; - } - - // Remove the current component from the hierarchy set - hierarchyVertices.pop(); - return comp; - } - } - } - } - } - - return currentComp; -}; - -/** - * Function: cycleStage - * - * Executes the cycle stage using mxMinimumCycleRemover. - */ -mxHierarchicalLayout.prototype.cycleStage = function(parent) -{ - var cycleStage = new mxMinimumCycleRemover(this); - cycleStage.execute(parent); -}; - -/** - * Function: layeringStage - * - * Implements first stage of a Sugiyama layout. - */ -mxHierarchicalLayout.prototype.layeringStage = function() -{ - this.model.initialRank(); - this.model.fixRanks(); -}; - -/** - * Function: crossingStage - * - * Executes the crossing stage using mxMedianHybridCrossingReduction. - */ -mxHierarchicalLayout.prototype.crossingStage = function(parent) -{ - var crossingStage = new mxMedianHybridCrossingReduction(this); - crossingStage.execute(parent); -}; - -/** - * Function: placementStage - * - * Executes the placement stage using mxCoordinateAssignment. - */ -mxHierarchicalLayout.prototype.placementStage = function(initialX, parent) -{ - var placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing, - this.interRankCellSpacing, this.orientation, initialX, - this.parallelEdgeSpacing); - placementStage.fineTuning = this.fineTuning; - placementStage.execute(parent); - - return placementStage.limitX + this.interHierarchySpacing; -}; |