UNPKG

markgojs

Version:

Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams

135 lines (112 loc) 5.66 kB
"use strict"; /* * Copyright (C) 1998-2019 by Northwoods Software Corporation. All Rights Reserved. */ // Contains PoolLink and BPMNLinkingTool classes for the BPMN sample // PoolLink, a special Link class for message flows from edges of pools function PoolLink() { go.Link.call(this); } go.Diagram.inherit(PoolLink, go.Link); /** @override */ PoolLink.prototype.getLinkPoint = function(node, port, spot, from, ortho, othernode, otherport) { var r = new go.Rect(port.getDocumentPoint(go.Spot.TopLeft), port.getDocumentPoint(go.Spot.BottomRight)); var op = go.Link.prototype.getLinkPoint.call(this, othernode, otherport, spot, from, ortho, node, port); var below = op.y > r.centerY; var y = below ? r.bottom : r.top; if (node.category === "privateProcess") { if (op.x < r.left) return new go.Point(r.left, y); if (op.x > r.right) return new go.Point(r.right, y); return new go.Point(op.x, y); } else { // otherwise get the standard link point by calling the base class method return go.Link.prototype.getLinkPoint.call(this, node, port, spot, from, ortho, othernode, otherport); } }; // If there are two links from & to same node... and pool is offset in X from node... the link toPoints collide on pool /** @override */ PoolLink.prototype.computeOtherPoint = function(othernode, otherport) { var op = go.Link.prototype.computeOtherPoint(this, othernode, otherport); var node = this.toNode; if (node === othernode) node = this.fromNode; if (othernode.category === "privateProcess") { op.x = node.getDocumentPoint(go.Spot.MiddleBottom).x; } else { if ((node === this.fromNode) ^ (node.actualBounds.centerY < othernode.actualBounds.centerY)) { op.x -= 1; } else { op.x += 1; } } return op; }; /** @override */ PoolLink.prototype.getLinkDirection = function(node, port, linkpoint, spot, from, ortho, othernode, otherport) { if (node.category === "privateProcess") { var p = port.getDocumentPoint(go.Spot.Center); var op = otherport.getDocumentPoint(go.Spot.Center); var below = op.y > p.y; return below ? 90 : 270; } else { return go.Link.prototype.getLinkDirection.call(this, node, port, linkpoint, spot, from, ortho, othernode, otherport); } }; // BPMNLinkingTool, a custom linking tool to switch the class of the link created. function BPMNLinkingTool() { go.LinkingTool.call(this); // don't allow user to create link starting on the To node this.direction = go.LinkingTool.ForwardsOnly; this.temporaryLink.routing = go.Link.Orthogonal; this.linkValidation = function(fromnode, fromport, tonode, toport) { return BPMNLinkingTool.validateSequenceLinkConnection(fromnode, fromport, tonode, toport) || BPMNLinkingTool.validateMessageLinkConnection(fromnode, fromport, tonode, toport); }; } go.Diagram.inherit(BPMNLinkingTool, go.LinkingTool); /** @override */ BPMNLinkingTool.prototype.insertLink = function(fromnode, fromport, tonode, toport) { var lsave = null; // maybe temporarily change the link data that is copied to create the new link if (BPMNLinkingTool.validateMessageLinkConnection(fromnode, fromport, tonode, toport)) { lsave = this.archetypeLinkData; this.archetypeLinkData = { category: "msg" }; } // create the link in the standard manner by calling the base method var newlink = go.LinkingTool.prototype.insertLink.call(this, fromnode, fromport, tonode, toport); // maybe make the label visible if (fromnode.category === "gateway") { var label = newlink.findObject("Label"); if (label !== null) label.visible = true; } // maybe restore the original archetype link data if (lsave !== null) this.archetypeLinkData = lsave; return newlink; }; // static utility validation routines for linking & relinking as well as insert link logic // in BPMN, can't link sequence flows across subprocess or pool boundaries BPMNLinkingTool.validateSequenceLinkConnection = function(fromnode, fromport, tonode, toport) { if (fromnode.category === null || tonode.category === null) return true; // if either node is in a subprocess, both nodes must be in same subprocess (not even Message Flows) if ((fromnode.containingGroup !== null && fromnode.containingGroup.category === "subprocess") || (tonode.containingGroup !== null && tonode.containingGroup.category === "subprocess")) { if (fromnode.containingGroup !== tonode.containingGroup) return false; } if (fromnode.containingGroup === tonode.containingGroup) return true; // a valid Sequence Flow // also check for children in common pool var common = fromnode.findCommonContainingGroup(tonode); return common != null; }; // in BPMN, Message Links must cross pool boundaries BPMNLinkingTool.validateMessageLinkConnection = function(fromnode, fromport, tonode, toport) { if (fromnode.category === null || tonode.category === null) return true; if (fromnode.category === "privateProcess" || tonode.category === "privateProcess") return true; // if either node is in a subprocess, both nodes must be in same subprocess (not even Message Flows) if ((fromnode.containingGroup !== null && fromnode.containingGroup.category === "subprocess") || (tonode.containingGroup !== null && tonode.containingGroup.category === "subprocess")) { if (fromnode.containingGroup !== tonode.containingGroup) return false; } if (fromnode.containingGroup === tonode.containingGroup) return false; // an invalid Message Flow // also check for children in common pool var common = fromnode.findCommonContainingGroup(tonode); return common === null; };