UNPKG

markgojs

Version:

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

140 lines (114 loc) 5.91 kB
"use strict"; /* * Copyright (C) 1998-2019 by Northwoods Software Corporation. All Rights Reserved. */ import * as go from "../release/go"; // Contains PoolLink and BPMNLinkingTool classes for the BPMN sample // PoolLink, a special Link class for message flows from edges of pools export class PoolLink extends go.Link { /** @override */ public getLinkPoint(node: go.Node, port: go.GraphObject, spot: go.Spot, from: boolean, ortho: boolean, othernode: go.Node, otherport: go.GraphObject) { 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 */ public computeOtherPoint(othernode: go.Node, otherport: go.GraphObject) { var op = super.computeOtherPoint(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 */ public getLinkDirection(node: go.Node, port: go.GraphObject, linkpoint: go.Point, spot: go.Spot, from: boolean, ortho: boolean, othernode: go.Node, otherport: go.GraphObject) { 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 super.getLinkDirection.call(this, node, port, linkpoint, spot, from, ortho, othernode, otherport); } }; } // BPMNLinkingTool, a custom linking tool to switch the class of the link created. export class BPMNLinkingTool extends go.LinkingTool { constructor() { super(); // don't allow user to create link starting on the To node this.direction = go.LinkingTool.ForwardsOnly; // orthogonal routing during linking this.temporaryLink.routing = go.Link.Orthogonal; // link validation using the validate methods defined below this.linkValidation = (fromnode: go.Node, fromport: go.GraphObject, tonode: go.Node, toport: go.GraphObject) => { return BPMNLinkingTool.validateSequenceLinkConnection(fromnode, fromport, tonode, toport) || BPMNLinkingTool.validateMessageLinkConnection(fromnode, fromport, tonode, toport); }; } /** @override */ public insertLink(fromnode: go.Node, fromport: go.GraphObject, tonode: go.Node, toport: go.GraphObject) { 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 = super.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 public static validateSequenceLinkConnection(fromnode: go.Node, fromport: go.GraphObject, tonode: go.Node, toport: go.GraphObject) { 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 public static validateMessageLinkConnection(fromnode: go.Node, fromport: go.GraphObject, tonode: go.Node, toport: go.GraphObject) { 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; }; }