UNPKG

@syncfusion/ej2-diagrams

Version:

Feature-rich diagram control to create diagrams like flow charts, organizational charts, mind maps, and BPMN diagrams. Its rich feature set includes built-in shapes, editing, serializing, exporting, printing, overview, data binding, and automatic layouts.

323 lines (322 loc) 15.4 kB
var FlowchartModel = /** @class */ (function () { function FlowchartModel(layout, root, vertices) { var _this = this; this.dfsCount = 0; this.maxRank = 100000000; this.layout = layout; this.vertexMapper = new Map(); this.ranks = new Map(); var internalVertices = []; this.createInternalCells(vertices, internalVertices); internalVertices.forEach(function (internalVertex) { var edges = internalVertex.internalOutEdges; edges.forEach(function (internalEdge) { var realEdges = internalEdge.edges; if (realEdges && realEdges.length > 0) { var realEdge = realEdges[0]; var targetCell = _this.layout.getVisibleTerminal(realEdge, false); var internalTargetCell = _this.vertexMapper.get(targetCell.id); if (internalVertex === internalTargetCell) { targetCell = _this.layout.getVisibleTerminal(realEdge, true); internalTargetCell = _this.vertexMapper.get(targetCell.id); } if (internalTargetCell && internalVertex !== internalTargetCell) { internalEdge.target = internalTargetCell; if (internalVertex.internalInEdges.indexOf(internalEdge) === -1) { internalTargetCell.internalInEdges.push(internalEdge); } } } }); }); this.rootNode = this.vertexMapper.get(root.id); } FlowchartModel.prototype.createInternalCells = function (vertices, internalVertices) { for (var j = 0; j < vertices.length; j++) { var vertex = vertices[parseInt(j.toString(), 10)]; var internalVertex = { tempRank: -1, cell: vertex, hashCode: [], maxRank: null, minRank: null, id: vertex.id, internalOutEdges: [], internalInEdges: [], identicalSibling: [] }; internalVertices.push(internalVertex); this.vertexMapper.set(vertex.id, internalVertex); var connectors = this.layout.getEdges(vertex); var i = 0; while (i < connectors.length) { var connector = connectors[parseInt(i.toString(), 10)]; var childVertex = this.layout.getVisibleTerminal(connector, false); if (childVertex !== vertex) { var undirectedEdges = this.layout.getEdgesBetween(vertex, childVertex, true); if (undirectedEdges.length > 0) { var internalEdge = { connectorIds: [], edges: undirectedEdges, ids: [], isReversed: false, source: null, target: null, tempRank: 0, maxRank: null, minRank: null }; for (var k = 0; k < undirectedEdges.length; k++) { var undirectedEdge = undirectedEdges[parseInt(k.toString(), 10)]; // if (!undirectedEdge.id) { // undirectedEdge.id = randomId(); // } internalEdge.ids.push(undirectedEdge.id); if (connectors.indexOf(undirectedEdge) !== -1) { if (connectors.indexOf(undirectedEdge) < i) { i--; } connectors.splice(connectors.indexOf(undirectedEdge), 1); } } internalEdge.source = internalVertex; if (internalVertex.internalOutEdges.indexOf(internalEdge) === -1) { internalVertex.internalOutEdges.push(internalEdge); } } } else { i++; } } } }; //Initializes the ranks of the vertices /** * @Private * @returns { void } Initializes the ranks of the vertices .\ */ FlowchartModel.prototype.layeringStage = function () { this.recycleConnectors(); this.initialRank(); this.fixRanks(); }; FlowchartModel.prototype.recycleConnectors = function () { var startNodes = [this.rootNode]; this.visit(startNodes, true); }; FlowchartModel.prototype.initialRank = function () { var startNodes = [this.rootNode]; var internalNodes = Array.from(this.vertexMapper.values()); while (startNodes.length > 0) { var internalNode = startNodes[0]; var outEdges = internalNode.internalOutEdges; var inEdges = internalNode.internalInEdges; var allEdgesScanned = true; var minimumLayer = 100000000; for (var i = 0; i < inEdges.length; i++) { var internalEdge = inEdges[parseInt(i.toString(), 10)]; if (internalEdge.tempRank === 5270620) { // This edge has been scanned, get the layer of the node on the other end var otherNode = internalEdge.source; minimumLayer = otherNode.tempRank ? Math.min(minimumLayer, otherNode.tempRank - 1) : minimumLayer; } else { allEdgesScanned = false; break; } } // If all edge have been scanned, assign the layer, mark all edges in the other direction and remove from the nodes list if (allEdgesScanned) { internalNode.tempRank = minimumLayer; this.maxRank = Math.min(this.maxRank, minimumLayer); if (outEdges.length) { if (internalNode.cell.isDecisionNode) { var yesChild = outEdges.find(function (e) { return e.target.cell.isYesChild; }); var decisionNode = outEdges.find(function (e) { return e.target.cell.isDecisionNode; }); if (outEdges.indexOf(decisionNode) === -1 && outEdges.indexOf(yesChild) !== 0) { outEdges.reverse(); } if (this.layout.yesBranchDirection === 'RightInFlow' || (this.layout.yesBranchDirection === 'SameAsFlow' && this.layout.noBranchDirection === 'LeftInFlow')) { outEdges.reverse(); } } for (var i = 0; i < outEdges.length; i++) { var internalEdge = outEdges[parseInt(i.toString(), 10)]; internalEdge.tempRank = 5270620; // Add node on other end of edge to LinkedList of nodes to be analysed var otherNode = internalEdge.target; // Only add node if it hasn't been assigned a layer if (otherNode.tempRank === -1) { // Mark this other node as neither being unassigned nor assigned //so it isn't added to this list again, but it's layer isn't used in any calculation. otherNode.tempRank = -2; startNodes.push(otherNode); } } } startNodes.shift(); } else { // Not all the edges have been scanned, get to the back of the class and put the dunces cap on var removedCell = startNodes.shift(); startNodes.push(internalNode); if (removedCell === internalNode && startNodes.length === 1) { // This is an error condition, we can't get out of this loop. //It could happen for more than one node but that's a lot harder to detect. Log the error break; } } } for (var i = 0; i < internalNodes.length; i++) { internalNodes[parseInt(i.toString(), 10)].tempRank -= this.maxRank; } var currentMaxLayer = 0; var layerDeterminingEdges = this.rootNode.internalOutEdges; for (var j = 0; j < layerDeterminingEdges.length; j++) { var internalEdge = layerDeterminingEdges[parseInt(j.toString(), 10)]; var otherNode = internalEdge.target; this.rootNode.tempRank = (otherNode.tempRank !== undefined && otherNode.tempRank !== null) ? Math.max(currentMaxLayer, otherNode.tempRank + 1) : currentMaxLayer; currentMaxLayer = this.rootNode.tempRank; } this.maxRank = 100000000 - this.maxRank; }; FlowchartModel.prototype.fixRanks = function () { var rankList = new Map(); this.ranks = new Map(); for (var i = 0; i <= this.maxRank; i++) { rankList.set(i, []); this.ranks.set(i, rankList.get(i)); } var rootsArray = [this.rootNode]; this.visit(rootsArray, false, rankList); }; /** * used to visit all the entries on the given dictionary with given function \ * * @returns { void } used to visit all the entries on the given dictionary with given function .\ * @param {InternalVertex[]} dfsRoots - provide the dfsRoots value. * @param {boolean} trackAncestors - provide the trackAncestors value. * @param {Map<number, []>} rankList - provide the rankList value. * @private */ FlowchartModel.prototype.visit = function (dfsRoots, trackAncestors, rankList) { if (rankList === void 0) { rankList = null; } if (dfsRoots) { for (var i = 0; i < dfsRoots.length; i++) { var internalNode = dfsRoots[parseInt(i.toString(), 10)]; if (internalNode) { var seenNodes = new Map(); if (trackAncestors) { internalNode.hashCode = [this.dfsCount, i]; this.extendedDfs(null, internalNode, null, seenNodes, i); } else { this.depthFirstSearch(null, internalNode, null, seenNodes, rankList); } } } this.dfsCount++; } }; FlowchartModel.prototype.extendedDfs = function (parent, root, connectingEdge, seen, childHash) { var _this = this; if (parent) { if (!root.hashCode || root.hashCode[0] !== parent.hashCode[0]) { root.hashCode = parent.hashCode.concat([childHash]); } } var rootId = root.id; if (!seen.has(rootId)) { seen.set(rootId, root); this.removeConnectionEdge(parent, root, connectingEdge); var outgoingEdges = root.internalOutEdges.slice(); outgoingEdges.forEach(function (internalEdge, i) { var targetNode = internalEdge.target; _this.extendedDfs(root, targetNode, internalEdge, seen, i); }); } else { this.removeConnectionEdge(parent, root, connectingEdge); } }; FlowchartModel.prototype.removeConnectionEdge = function (parent, node, connectingEdge) { if (parent && this.isAncestor(node, parent)) { this.invert(connectingEdge); this.remove(connectingEdge, parent.internalOutEdges); parent.internalInEdges.push(connectingEdge); this.remove(connectingEdge, node.internalInEdges); node.internalOutEdges.push(connectingEdge); } }; FlowchartModel.prototype.invert = function (edge) { var temp = edge.source; edge.source = edge.target; edge.target = temp; edge.isReversed = !edge.isReversed; }; FlowchartModel.prototype.remove = function (edge, edges) { var index = edges.indexOf(edge); edges.splice(index, 1); }; FlowchartModel.prototype.isAncestor = function (node, otherNode) { // Firstly, the hash code of this node needs to be shorter than the other node if (otherNode !== null && node.hashCode !== null && otherNode.hashCode !== null && node.hashCode.length < otherNode.hashCode.length) { if (node.hashCode === otherNode.hashCode) { return true; } for (var i = 0; i < node.hashCode.length; i++) { if (node.hashCode[parseInt(i.toString(), 10)] !== otherNode.hashCode[parseInt(i.toString(), 10)]) { return false; } } return true; } return false; }; FlowchartModel.prototype.depthFirstSearch = function (parent, root, connectingEdge, seen, rankList) { var _this = this; var rootId = root.id; if (!seen.has(rootId)) { seen.set(rootId, root); this.updateMinMaxRank(parent, root, connectingEdge, 0, rankList); var outgoingEdges = root.internalOutEdges.slice(); outgoingEdges.forEach(function (internalEdge) { var targetNode = internalEdge.target; _this.depthFirstSearch(root, targetNode, internalEdge, seen, rankList); }); } else { this.updateMinMaxRank(parent, root, connectingEdge, 1, rankList); } }; FlowchartModel.prototype.updateMinMaxRank = function (parent, node, edge, seen, rankList) { var rankListArray = Array.from(rankList.values()); if (node.maxRank == null && node.maxRank !== 0) { node.maxRank = -1; } if (node.minRank == null && node.minRank !== 0) { node.minRank = -1; } if (seen === 0 && node.maxRank < 0 && node.minRank < 0) { if (node.tempRank >= 0) { var rank = node.tempRank; rankListArray[parseInt(rank.toString(), 10)].push(node); node.maxRank = rank; node.minRank = rank; node.tempRank = rankListArray[node.maxRank].length - 1; } } if (parent !== null && edge !== null) { var parentToCellRankDifference = parent.maxRank - node.maxRank; if (parentToCellRankDifference > 1) { edge.maxRank = parent.maxRank; edge.minRank = node.maxRank; for (var i = edge.minRank + 1; i < edge.maxRank; i++) { rankListArray[parseInt(i.toString(), 10)].push(edge); // CheckMe // this.layout.setTempVariable(edge, i, rankList[i].length - 1); } } else if (edge.isReversed) { edge.maxRank = parent.maxRank; edge.minRank = node.maxRank; for (var i = edge.minRank; i <= edge.maxRank; i++) { rankListArray[parseInt(i.toString(), 10)].push(edge); } } } }; return FlowchartModel; }()); export { FlowchartModel };